我有一个数据表,通过使用函数 searchStringToRegexString 将搜索字符串转换为正则表达式,我在其中建立了自定义搜索逻辑(使用 AND 和 OR)。然后,以下搜索字符串将转换为:
'term1 AND term2' => (?=.*term1)(?=.*term2)
'term1 OR term2' => (?=.*term1)|(?=.*term2)
'term1 term2' => (?=.*term1 term2)
'term1 term2 OR term3 AND term4' => (?=.*term1 term2)|(?=.*term3)(?=.*term4)
虽然自定义搜索按列搜索的预期工作,但我在全局搜索中遇到以下问题:
(A.) 全局搜索“ford ORdog”效果很好。然而,“ma AND cat”显示零结果,这是不正确的。
(B.) 此外,当切换到列搜索(例如,切换到“pet”列)并输入搜索“cat”时,显示的全局搜索字符串从“ma AND cat”更改为“(?=.*ma )(?=.*猫)".
为了解决该问题,我取消了分配的事件处理程序的绑定。但是,全局搜索似乎无法正确解释正则表达式字符串。
如果有人可以给我一些关于如何解决全局搜索的正则表达式搜索的建议。
library(DT)
library(shiny)
ui = fluidPage(
shiny::tags$script("
function searchStringToRegexString(search_str) {
let term_before = false;
let regex_str = '(?=.*';
let parts = search_str.trim().split(' '); // array with terms split by spaces
for (let part of parts) {
if ((part === 'AND') || (part === 'OR')) {
regex_str += (part === 'AND') ? ')(?=.*' : ')|(?=.*'; // 'term1 AND term2' => (?=.*term1)(?=.*term2), 'term1 OR term2' => (?=.*term1)|(?=.*term2)
term_before = false;
} else {
regex_str += (term_before === true) ? (' ' + part) : part; // 'term1 term2' => (?=.*term1 term2)
term_before = true;
}
}
regex_str += ')';
regex_str = regex_str.replace('|(?=.*)', '').replace('(?=.*)', ''); // remove empty ANDs and ORs
console.log('search_str:', search_str, ', regex_str:', regex_str);
return regex_str;
}
"),
fluidRow(
column(width = 12,
DTOutput("dtable")
)
)
)
server = function(input, output, session) {
data = data.frame(
car = c("Mazda", "Mazda RX4", "Mazda RX4 Wag", "Ford", "Mercedes"),
pet = c("dog", "dog", "cat", "cat", "cat")
)
output$dtable = renderDT({
datatable(
data,
filter = list(position = "top", clear = TRUE, plain = FALSE),
options = list(
searchDelay = 1500,
dom = "ft",
columnDefs = list(list(targets = "_all", className = "dt-center")),
fixedHeader = FALSE,
initComplete = JS("
function(settings) {
let glo_search_handler = $('.dataTables_filter input');
let instance = settings.oInstance;
let col_search_handler = instance.parent().find('.form-group input');
let table = instance.api();
col_search_handler.unbind(); // unbind the default datatable search handlers
glo_search_handler.unbind();
glo_search_handler.on('keyup.globalSearch', function(e) { // global search handler
e.preventDefault(); // prevent the default form submit behavior
let glo_search_str = $(this).val().trim();
if (glo_search_str === '') {
table.search('').draw();
} else {
let glo_regex_str = searchStringToRegexString(glo_search_str);
table.search(glo_regex_str, true, false, true).draw(); // search term, regex, smart, caseInsensitive
}
});
col_search_handler.on('keyup.columnSearch', function(e) { // custom column search handler
e.preventDefault(); // prevent the default form submit behavior
let col_search_str = $(this).val().trim();
let index = 1 + col_search_handler.index(this);
let column = table.column(index);
if (col_search_str === '') {
column.search('').draw();
} else {
let col_regex_str = searchStringToRegexString(col_search_str);
column.search(col_regex_str, true, false, true).draw();
}
});
}
")
)
)
}, server = TRUE)
}
shinyApp(ui = ui, server = server)
虽然将“and”字符串翻译为像
(?=.*term1)(?=.*term2)
这样的正则表达式在技术上是正确的,但它不适用于服务器端 DT
搜索的实现。但是,如果您启用了 smart
搜索(在示例中自动)并在括号之间插入空格:
(?=.*term1) (?=.*term2)
更改
global
搜索字符串的另一个问题与 draw()
有关,可以通过暂时保存该值并在 draw()
之后重新分配来避免:
let currentGlobalSearchString = $('.dataTables_filter input').val();
column.search(col_regex_str, true, false, true).draw();
$('.dataTables_filter input').val(currentGlobalSearchString);