在基于Shiny的DT表格中,如何根据正则表达式高亮显示单词?

9
使用DT在shiny中,我想要能够突出显示所选单词。设置searchHighlight = TRUE接近我想要的效果,但这也会突出显示包含搜索的单词。例如,如果我正在搜索“on”,它还将匹配“stone”,并突出显示中间的“on”。
示例图像:

Words within words being highlighted

我可以调整搜索选项,使regex = TRUE,但是然后就不会发生高亮显示。如果我想使用正则表达式比如“on|in”,这也是正确的。
示例(包括正则表达式):
library(shiny)
library(DT)
library(data.table)

example_data <- data.table(words = c("on", "scone", "wrong", "stone"), 
                           description = c("The word on", "Scone is not on.", "Not on either", "Not here at all"))

ui = shinyUI(fluidPage(

  sidebarLayout(
    sidebarPanel(
      textInput("word_select", label = "Word to search")
      ),
    mainPanel(
      dataTableOutput("word_searched")
    )
  )
))

server = shinyServer(function(input, output, session) {

  output$word_searched <- renderDataTable({
    datatable(
      example_data, 
      options = list(searchHighlight = TRUE, 
                     search = list(regex = TRUE, 
                                   search = paste0("\\b", tolower(input$word_select), "\\b")))
    )
  })

  })

shinyApp(ui = ui, server = server)

DT已经通过反应表达式过滤了该单词,因此所有字段肯定都包括所选单词,但我只是想避免用户误认为搜索错误地包括了更长的单词而产生混淆。虽然在示例中我还没有这样做,但只是确认这不是我关心的元素。

感谢您的帮助。

(编辑以添加一个在示例数据中带有标点符号的单词示例。)

2个回答

9

不要依赖datatable的搜索功能,你可以创建一个reactive元素,先通过输入筛选,然后用嵌入在<span style="background-color:yellow;">标签中的相同单词替换匹配的单词。这样可以通过更复杂的正则表达式实现更灵活的搜索。

您需要在datatable中添加escape = F,以便正确解释HTML标记。我已经在datatable中添加了options = list(dom = "lt"),以删除datatable的搜索字段并将注意力集中在左侧搜索字段上。

过滤标准保持相当模糊,以避免表格在找到完全匹配之前消失 - 即当您键入“o”时,表格不应该消失,然后在“on”处重新出现。然后只有在找到匹配的单词时才会出现高亮,例如onOnon.,而不包括stonescone等。以下是它的外观:

enter image description here

这是代码。请注意,我使用dplyr的过滤和变换函数,因为它们可以通过它们的*_all变体轻松应用于多个列:

library(shiny)
library(DT)
library(data.table)
library(dplyr) # For `filter_all` and `mutate_all`.

example_data <- iris
    # data.table(words = c("on", "scone", "wrong", "stone"), 
    #                        description = c("The word on", "Scone is not on.", "Not on either", "Not here at all"))

ui = shinyUI(fluidPage(

    sidebarLayout(
        sidebarPanel(
            textInput("word_select", label = "Word to search")
        ),
        mainPanel(
            dataTableOutput("word_searched")
        )
    )
))

server = shinyServer(function(input, output, session) {

    # This is your reactive element.
    df_reactive <- reactive({
            example_data %>%
                # Filter if input is anywhere, even in other words.
                filter_all(any_vars(grepl(input$word_select, ., T, T))) %>% 
                # Replace complete words with same in HTML.
                mutate_all(~ gsub(
                              paste(c("\\b(", input$word_select, ")\\b"), collapse = ""),
                              "<span style='background-color:yellow;'>\\1</span>",
                              .,
                              TRUE,
                              TRUE
                              )
                          )
    })

    # Render your reactive element here.
    output$word_searched <- renderDataTable({
        datatable(df_reactive(), escape = F, options = list(dom = "lt"))
    })

})

shinyApp(ui = ui, server = server)

1
谢谢,这基本上可以工作!它不一定适用于正则表达式元素,但我认为我可以用这种方法解决这个问题。注意,我使用了以下代码来保持使用data.table(不过滤,因为我不需要,但类似的方法也是可能的):example_data_dt[, lapply(.SD, function(x) gsub( paste0("\\b(", input$word_select, ")\\b"), "<span style='background-color:yellow;'>\\1</span>", x, TRUE, TRUE ))] - Jaccar
1
我非常欣赏这种从不同角度(而非在DT内部)来看待问题的方式 :) - Jaccar
@Megan 很高兴听到它能够正常工作!这种策略的优点在于你可以做的事情没有那么多限制。例如,使用 if-else 条件语句,你可以为部分匹配使用一种颜色,为完全匹配使用另一种颜色等等。我可能错了,但 datatable 的内置搜索高亮功能看起来并不是很灵活。 - user10191355
@gersht非常感谢您提供的正则表达式,它非常有用!我稍微修改了您的代码,使其仅适用于我的数据集中的一列:“mutate(caption = gsub(pattern = paste(c("\b(", input$filter_captions, ")\b"), collapse = ""), replacement = "<span style='background-color: #F08080;'>\1</span>", x = data_insta_filtered$caption))"。 但是,我有一个问题:您知道如何突出显示与我的选择匹配的单词的一部分而不仅仅是整个单词吗?非常感谢! - nd091680

2
我不确定这是否完全符合您的要求,但我认为很接近:它并不能执行精确搜索(例如,“on”会匹配“stone”),但它只会突出显示精确匹配项(例如,“on”不会被突出显示)。这使用了mark.js库。最初的回答。
dtable <- datatable(iris[c(1,2,51,52,101,102),], 
                    options = list(
                      mark = list(accuracy = "exactly")
                    )
)
dep1 <- htmltools::htmlDependency(
  "datatables.mark", "2.0.1", 
  src = c(href = "https://cdn.datatables.net/plug-ins/1.10.19/features/mark.js"),
  script = "datatables.mark.min.js")
dep2 <- htmltools::htmlDependency(
  "jquery.mark", "8.11.1", 
  src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1"), 
  script = "jquery.mark.min.js")
dtable$dependencies <- c(dtable$dependencies, list(dep1, dep2))
dtable

enter image description here


谢谢!这看起来很有前途。我已经在闪亮的应用程序中检查了它,几乎可以工作。我注意到的一件事是,它不会突出带有标点符号的单词-例如,如果单词是类似"(on)"的东西,或者在句子结尾处像"on."这样。你知道如何处理吗?另外(并且不那么重要),是否有办法更改突出显示的颜色?我的屏幕上是非常苍白的黄色,不够明亮,不能真正突出。 - Jaccar
@Megan 在这里查看文档(https://markjs.io/)。你可以使用CSS控制颜色。至于标点符号,我不确定。 - Stéphane Laurent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接