【问题标题】:R grep: Match one string against multiple patternsR grep:将一个字符串与多个模式匹配
【发布时间】:2012-03-21 05:19:33
【问题描述】:

在 R 中,grep 通常将多个字符串的向量与一个正则表达式匹配。

问:是否有可能将单个字符串与多个正则表达式匹配? (不循环每个正则表达式模式)?

一些背景:

我有 7000 多个关键字作为几个类别的指标。我无法更改该关键字字典。字典结构如下(第1列的关键词,数字表示这些关键词所属的类别):

ab  10  37  41
abbrach*    38
abbreche    39
abbrich*    39
abend*  37
abendessen* 60  63
aber    20  23  45
abermals    37

用“|”连接这么多关键字不是一种可行的方法(而且我不知道哪个关键字产生了命中)。 此外,仅仅颠倒“模式”和“字符串”是行不通的,因为模式有截断,反过来也行不通。

[related question,其他编程语言]

【问题讨论】:

  • 我喜欢 dan 的建议,但是对于大型数据集,您可能会遇到一些重大的速度问题。如果您想在字典中查找某些内容并返回相应的值,我建议采用不同的方法:使用 strsplit 将句子分解为单个单词的向量,然后应用哈希表进行快速查找。我认为您可能还希望将关键字和类别指示符分成字典中的两个单独的列。我会在那里提供帮助,但前提是您更清楚最终结果是需要。
  • 同意重组字典数据并使用哈希表进行查找(取决于期望的结果),但匹配应该相对较快取决于字符串的数量,即使有大量的关键字.我将在我的答案中添加一个快速基准。
  • 如果你真的有很多单词(通常是人类语言中的所有单词,google索引的所有单词等),你可以使用prefix tree(有时也称为“特里”)。但我不知道 R 中有任何实现。

标签: regex r


【解决方案1】:

re2r 包可以匹配多个模式(并行)。最小的例子:

# compile patterns
re <- re2r::re2(keywords)
# match strings
re2r::re2_detect(strings, re, parallel = TRUE)

【讨论】:

    【解决方案2】:

    要扩展other answer,将sapply() 输出转换为有用的逻辑向量,您需要进一步使用apply() 步骤。

    keywords <- c("dog", "cat", "bird")
    strings <- c("Do you have a dog?", "My cat ate by bird.", "Let's get icecream!")
    (matches <- sapply(keywords, grepl, strings, ignore.case=TRUE))
    #        dog   cat  bird
    # [1,]  TRUE FALSE FALSE
    # [2,] FALSE  TRUE  TRUE
    # [3,] FALSE FALSE FALSE
    

    要知道哪些字符串包含任何个关键字(模式):

    apply(matches, 1, any)
    # [1]  TRUE  TRUE FALSE
    

    要知道在提供的字符串中匹配了哪些关键字(模式):

    apply(matches, 2, any)
    #  dog  cat bird 
    # TRUE TRUE TRUE
    

    【讨论】:

      【解决方案3】:

      如何将 regexpr 函数应用于关键字向量?

      keywords <- c("dog", "cat", "bird")
      
      strings <- c("Do you have a dog?", "My cat ate by bird.", "Let's get icecream!")
      
      sapply(keywords, regexpr, strings, ignore.case=TRUE)
      
           dog cat bird
      [1,]  15  -1   -1
      [2,]  -1   4   15
      [3,]  -1  -1   -1
      
          sapply(keywords, regexpr, strings[1], ignore.case=TRUE)
      
       dog  cat bird 
        15   -1   -1 
      

      返回值是匹配中第一个字符的位置,-1 表示不匹配。

      如果匹配的位置无关紧要,请改用grepl

      sapply(keywords, grepl, strings, ignore.case=TRUE)
      
             dog   cat  bird
      [1,]  TRUE FALSE FALSE
      [2,] FALSE  TRUE  TRUE
      [3,] FALSE FALSE FALSE
      

      更新:这在我的系统上运行相对较快,即使有大量关键字:

      # Available on most *nix systems
      words <- scan("/usr/share/dict/words", what="")
      length(words)
      [1] 234936
      
      system.time(matches <- sapply(words, grepl, strings, ignore.case=TRUE))
      
         user  system elapsed 
        7.495   0.155   7.596 
      
      dim(matches)
      [1]      3 234936
      

      【讨论】:

      • 感谢您的回答和您的 cmets!最后,我做了一个组合方法:trie 将可能匹配的集合减少到原始大小的 5%,而 sapply 函数执行 grep。
      • 然后为了查看每个句子/字符串有多少关键字匹配,在最终数据帧上,发出:num.matches
      • 如果你想做一个替换,你不仅要阅读要搜索的关键字,还要阅读它们的替换?
      猜你喜欢
      • 2012-04-01
      • 1970-01-01
      • 2022-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多