匹配多个模式

26

我想查看一个由0和1组成的4个字符的字符串中是否出现了"001""100""000"。例如,一个4个字符的字符串可能是"1100""0010""1001""1111"。怎样用单个命令匹配字符串中的多个字符串?

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

6个回答

49

可以的。在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

请参阅?regex以获取有关在R中使用正则表达式的帮助。


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

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

4
我从痛苦的经历中学到,R 里没有什么是不可能的。问题总是在于如何做到! - Andrie

7

这里有一个使用stringr包的解决方案。

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

3

使用-e参数添加额外的模式:

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

2
很抱歉,但我忘了提到我想在R中完成这个。 - Narayani
这个无论如何都很有用。 - marbel

2
如果您想要逻辑向量,则应该查看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

2

抱歉,我需要另外回答,因为这篇文章太长了,无法在评论中回答。

我想提醒一下,通过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,即 result <- grepl(paste(words, collapse = "|"), text, perl = T) - ishonest

1
您还可以使用来自 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%“参数:...模式传递给grepl。”至少到data.table版本1.10.4-2。 - Manuel Bickel

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