【问题标题】:Matching multiple patterns匹配多个模式
【发布时间】:2011-10-20 07:51:42
【问题描述】:

我想看看,"001""100""000" 是否出现在 01 的 4 个字符的字符串中。例如,一个 4 字符的字符串可能是 "1100""0010""1001""1111"。如何使用单个命令匹配字符串中的多个字符串?

我知道 grep 可以用于模式匹配,但是使用 grep,我一次只能检查一个字符串。我想知道多个字符串是否可以与其他命令或 grep 本身一起使用。

【问题讨论】:

    标签: r regex


    【解决方案1】:

    很抱歉将其作为附加答案,但评论的行数过多。

    我只是想提醒一下,可以通过paste(..., collapse = "|") 粘贴在一起以用作单个匹配模式的项目数量是有限的 - 见下文。也许有人可以告诉确切的限制在哪里?诚然,这个数字可能不现实,但根据要执行的任务,它不应完全排除在我们的考虑之外。

    对于非常多的项目,需要一个循环来检查模式的每个项目。

    set.seed(0)
    samplefun <- function(n, x, collapse){
      paste(sample(x, n, replace=TRUE), collapse=collapse)
    }
    
    words <- sapply(rpois(10000000, 8) + 1, samplefun, letters, '')
    text <- sapply(rpois(1000, 5) + 1, samplefun, words, ' ')
    
    #since execution takes a while, I have commented out the following lines
    
    #result <- grepl(paste(words, collapse = "|"), text)
    
    # Error in grepl(pattern, text) : 
    #   invalid regular expression 
    # 'wljtpgjqtnw|twiv|jphmer|mcemahvlsjxr|grehqfgldkgfu|
    # ...
    
    #result <- stringi::stri_detect_regex(text, paste(words, collapse = "|"))
    
    # Error in stringi::stri_detect_regex(text, paste(words, collapse = "|")) : 
    # Pattern exceeds limits on size or complexity. (U_REGEX_PATTERN_TOO_BIG)
    

    【讨论】:

    • 使用 perl = T,即结果
    【解决方案2】:

    是的,你可以。 grep 模式中的|or 具有相同的含义。因此,您可以使用 "001|100|000" 作为您的模式来测试您的模式。同时grep被向量化了,所以这一切都可以一步完成:

    x <- c("1100", "0010", "1001", "1111")
    pattern <- "001|100|000"
    
    grep(pattern, x)
    [1] 1 2 3
    

    这将返回您的哪些向量包含匹配模式的索引(在本例中为前三个。)

    有时,有一个逻辑向量会更方便,它可以告诉您向量中的哪些元素是匹配的。然后你可以使用grepl:

    grepl(pattern, x)
    [1]  TRUE  TRUE  TRUE FALSE
    

    有关 R 中的正则表达式的帮助,请参阅 ?regex


    编辑: 为了避免手动创建模式,我们可以使用paste:

    myValues <- c("001", "100", "000")
    pattern <- paste(myValues, collapse = "|")
    

    【讨论】:

    • @DavidArenburg :-) 我从痛苦的经历中学到,在 R 中没有什么是不可能的。这始终只是如何做的问题!
    【解决方案3】:

    如果你想要逻辑向量,那么你应该检查stringi 包中的stri_detect 函数。在你的情况下,模式是正则表达式,所以使用这个:

    stri_detect_regex(x, pattern)
    ## [1]  TRUE  TRUE  TRUE FALSE
    

    还有一些基准测试:

    require(microbenchmark)
    test <- stri_paste(stri_rand_strings(100000, 4, "[0-1]"))
    head(test)
    ## [1] "0001" "1111" "1101" "1101" "1110" "0110"
    microbenchmark(stri_detect_regex(test, pattern), grepl(pattern, test))
    Unit: milliseconds
                                 expr      min       lq     mean   median       uq      max neval
     stri_detect_regex(test, pattern) 29.67405 30.30656 31.61175 30.93748 33.14948 35.90658   100
                 grepl(pattern, test) 36.72723 37.71329 40.08595 40.01104 41.57586 48.63421   100
    

    【讨论】:

      【解决方案4】:

      您还可以使用 data.table 库中的 %like% 运算符。

      library(data.table)
      
      # input
        x <- c("1100", "0010", "1001", "1111")
        pattern <- "001|100|000"
      
      # check for pattern
        x %like% pattern
      
      > [1]  TRUE  TRUE  TRUE FALSE
      

      【讨论】:

      • 请注意%like% 只是grepl 的包装,请检查?%like% "Arguments: ... pattern Passed on to grepl."。至少达到data.table 1.10.4-2 版。
      【解决方案5】:

      这是使用stringr 包的一种解决方案

      require(stringr)
      mylist = c("1100", "0010", "1001", "1111")
      str_locate(mylist, "000|001|100")
      

      【讨论】:

        【解决方案6】:

        使用 -e 参数添加其他模式:

        echo '1100' | grep -e '001' -e '110' -e '101'
        

        【讨论】:

        • 对不起,我忘了说我想在 R 中做这个。
        • 这还是有用的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-21
        • 2017-04-11
        • 2013-05-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多