基于正则表达式在闪亮的 DT 中突出显示单词

Posted

技术标签:

【中文标题】基于正则表达式在闪亮的 DT 中突出显示单词【英文标题】:Highlight word in DT in shiny based on regex 【发布时间】:2019-10-31 04:24:35 【问题描述】:

在闪亮中使用 DT,我希望能够突出显示选定的单词。设置 searchHighlight = TRUE 接近我想要的,但这也会突出显示包含搜索的单词。例如,如果我搜索“on”,它也会匹配“stone”,突出显示中间的“on”。

示例图片:

我可以细化搜索选项,以便 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 已经被反应式表达式过滤在单词上,所以所有字段肯定会包含所选单词,但我只是想避免用户认为更长的单词被错误地包含在搜索中而造成混淆。我在示例中没有这样做,但只是确认这不是我关心的元素。

感谢您的帮助。

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

【问题讨论】:

【参考方案1】:

您可以创建一个reactive 元素,而不是依赖数据表的搜索功能,该元素首先按输入过滤,然后用嵌入在&lt;span style="background-color:yellow;"&gt; 标记中的相同单词替换匹配的单词。这应该允许通过更复杂的正则表达式实现更大的搜索灵活性。

您需要将escape = F 添加到datatable,以便正确解释html 标记。我已将 options = list(dom = "lt") 添加到 datatable 以删除数据表的搜索字段并将注意力指向左侧搜索字段。

过滤条件相当模糊,以防止表格消失,直到找到完美匹配 - 即当您键入“o”时表格不应消失,因为没有完美匹配,然后重新出现在“on”处。仅当找到匹配词时才会出现高亮显示,即 onOnon.,但不会出现 stonescone 等。以下是它的外观:

这是代码。请注意,我使用 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)

【讨论】:

谢谢,这基本上有效!它不一定适用于正则表达式元素,但我想我可以用这种方法解决这个问题。注意我使用以下代码进行反应以继续使用 data.table (不过滤,因为我不需要,但类似的方法是可能的):example_data_dt[, lapply(.SD, function(x) gsub( paste0("\\b(", input$word_select, ")\\b"), "&lt;span style='background-color:yellow;'&gt;\\1&lt;/span&gt;", x, TRUE, TRUE ))] 我真的很感激我从不同的角度来看待这个问题(从 DT 本身):) @Megan 很高兴听到它有效!这种策略还有一个优点,就是你可以做的限制更少。例如,使用 if-else 条件,您可以使用一种颜色进行部分匹配,使用另一种颜色进行完全匹配等。我可能弄错了,但 datatable 的内置搜索突出显示看起来不是很通用。 @gersht 非常感谢这个正则表达式,它真的很有用!我稍微修改了您的代码,使其仅适用于我的数据集的一列:mutate(caption = gsub(pattern = paste(c("\\b(", input$filter_captions, ")\\b"), collapse = ""), replacement = "&lt;span style='background-color: #F08080;'&gt;\\1&lt;/span&gt;", x = data_insta_filtered$caption))。但是,我有一个问题:您知道我如何不仅可以突出显示整个单词,还可以突出显示与我的选择匹配的单词的一小部分吗?非常感谢!【参考方案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

【讨论】:

谢谢!这看起来很有希望。我已经在闪亮的应用程序中检查了这个,它几乎可以工作。我注意到的一件事是它不会用标点符号突出显示单词 - 例如,如果单词是“(on)”之类的东西,或者位于“on”之类的句子末尾。你知道有什么办法处理吗?另外(不太重要)有没有办法改变高光颜色?我的是屏幕上的淡黄色,不够亮,无法真正脱颖而出。 @Megan 请参阅文档here。您可以使用 CSS 控制颜色。对于我不知道的标点符号。

以上是关于基于正则表达式在闪亮的 DT 中突出显示单词的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的正则表达式条件之前立即获得单词?

在 Python 中使用正则表达式查找和替换文件中的单词列表

如何在 Tkinter 文本搜索方法中使用正则表达式?

如何使用正则表达式匹配不以某些字符开头或结尾的单词?

正则表达式突出显示搜索匹配的数字

使用正则表达式突出显示文本中的链接(Linkify vs Patterns)