【问题标题】:grep using a character vector with multiple patternsgrep 使用具有多个模式的字符向量
【发布时间】:2011-11-27 16:39:19
【问题描述】:

我正在尝试使用grep 来测试字符串向量是否存在于另一个向量中,并输出存在的值(匹配模式)。

我有一个这样的数据框:

FirstName Letter   
Alex      A1
Alex      A6
Alex      A7
Bob       A1
Chris     A9
Chris     A6

我在“字母”列中有一个字符串模式向量,例如:c("A1", "A9", "A6")

我想检查“字母”列中是否存在模式向量中的任何字符串。如果是,我想要唯一值的输出。

问题是,我不知道如何将grep 与多个模式一起使用。我试过了:

matches <- unique (
    grep("A1| A9 | A6", myfile$Letter, value=TRUE, fixed=TRUE)
)

但它给了我 0 个不正确的匹配项,有什么建议吗?

【问题讨论】:

  • 你不能使用 fixed=TRUE 因为你的模式是 true 正则表达式。
  • 使用match%in% 甚至== 是比较精确匹配的唯一正确方法。正则表达式对于这样的任务是非常危险的,并且可能导致意想不到的结果。

标签: r regex


【解决方案1】:

这应该可行:

grep(pattern = 'A1|A9|A6', x = myfile$Letter)

或者更简单:

library(data.table)
myfile$Letter %like% 'A1|A9|A6'

【讨论】:

  • %like% 不在基础 R 中,因此您应该提及使用它需要哪些包。
  • 对于查看此答案的其他人,%like%data.table 包的一部分。在data.table 中也类似的还有like(...)%ilike%%flike%
【解决方案2】:

除了@Marek 关于不包括fixed==TRUE 的评论之外,您还需要在正则表达式中没有空格。应该是"A1|A9|A6"

您还提到有很多模式。假设它们在一个向量中

toMatch <- c("A1", "A9", "A6")

然后您可以直接使用pastecollapse = "|" 创建您的正则表达式。

matches <- unique (grep(paste(toMatch,collapse="|"), 
                        myfile$Letter, value=TRUE))

【讨论】:

  • 当您的字符串列表包含正则表达式运算符作为标点符号时,有什么方法可以做到这一点?
  • @user1987097 它应该以相同的方式工作,有或没有任何其他正则表达式运算符。你有一个不适用的具体例子吗?
  • @user1987097 在点或括号前使用 2 个反斜杠。第一个反斜杠是一个转义字符,用于解释禁用运算符所需的第二个反斜杠。
  • 使用正则表达式进行完全匹配对我来说似乎很危险,并且可能会产生意想不到的结果。为什么不只是toMatch %in% myfile$Letter
  • @user4050 没有具体原因。问题中的版本有它,我可能只是通过它而不考虑是否有必要。
【解决方案3】:

去掉空格。这样做:

matches <- unique(grep("A1|A9|A6", myfile$Letter, value=TRUE, fixed=TRUE))

【讨论】:

    【解决方案4】:

    使用sapply

     patterns <- c("A1", "A9", "A6")
             df <- data.frame(name=c("A","Ale","Al","lex","x"),Letters=c("A1","A2","A9","A1","A9"))
    
    
    
       name Letters
    1    A      A1
    2  Ale      A2
    3   Al      A9
    4  lex      A1
    5    x      A9
    
    
     df[unlist(sapply(patterns, grep, df$Letters, USE.NAMES = F)), ]
      name Letters
    1    A      A1
    4  lex      A1
    3   Al      A9
    5    x      A9
    

    【讨论】:

      【解决方案5】:

      不确定这个答案是否已经出现...

      对于问题中的特定模式,您可以通过单个 grep() 调用来完成,

      grep("A[169]", myfile$Letter)
      

      【讨论】:

        【解决方案6】:

        很好的答案,但不要忘记来自 dplyr 的 filter()

        patterns <- c("A1", "A9", "A6")
        >your_df
          FirstName Letter
        1      Alex     A1
        2      Alex     A6
        3      Alex     A7
        4       Bob     A1
        5     Chris     A9
        6     Chris     A6
        
        result <- filter(your_df, grepl(paste(patterns, collapse="|"), Letter))
        
        >result
          FirstName Letter
        1      Alex     A1
        2      Alex     A6
        3       Bob     A1
        4     Chris     A9
        5     Chris     A6
        

        【讨论】:

        • 我认为 grepl 当时使用一种模式(我们需要长度为 1 的向量),我们有 3 种模式(长度为 3 的向量),因此我们可以使用一些将它们与一种模式结合对 grepl 分隔符友好 - |,试试你的运气吧:)
        • 哦,我现在明白了。所以它是一种输出类似 A1 | 的压缩方式A2 因此,如果想要所有条件,那么崩溃将带有 & 符号,很酷,谢谢。
        • 嗨,使用)|( 来分隔模式可能会使其更加健壮:paste0("(", paste(patterns, collapse=")|("),")")。不幸的是,它也变得不那么优雅了。这导致模式(A1)|(A9)|(A6)
        【解决方案7】:

        我建议编写一个小脚本并使用 Grep 进行多次搜索。我从来没有找到一种方法来搜索多种模式,相信我,我已经看过了!

        像这样,你的 shell 文件,带有一个嵌入的字符串:

         #!/bin/bash 
         grep *A6* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";
         grep *A7* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";
         grep *A8* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";
        

        然后通过键入 myshell.sh 运行。

        如果您希望能够在命令行中传递字符串,请像这样使用 shell 参数——顺便说一句,这是 bash 表示法:

         #!/bin/bash 
         $stingtomatch = "${1}";
         grep *A6* "${stingtomatch}";
         grep *A7* "${stingtomatch}";
         grep *A8* "${stingtomatch}";
        

        等等。

        如果有很多模式要匹配,你可以把它放在一个 for 循环中。

        【讨论】:

        • 谢谢克里斯宾。这些模式实际上很多,那么使用文件可能会更好。我是 BASH 的新手,但也许这样的东西应该可以工作...... #!/bin/bash for i in 'pattern.txt' do echo $ij='grep -c "${i}" myfile.txt' echo $j如果 [$j -eq o ] 那么 echo $i >> matches.txt fi done
        • 不起作用...错误消息是“[grep: command not found”...我在 /bin 文件夹中有 grep,并且 /bin 在我的 $PATH 上...不确定发生了什么...你能帮忙吗?
        【解决方案8】:

        添加到 Brian Diggs 的答案。

        另一种使用 grepl 的方法将返回一个包含所有值的数据框。

        toMatch <- myfile$Letter
        
        matches <- myfile[grepl(paste(toMatch, collapse="|"), myfile$Letter), ]
        
        matches
        
        Letter Firstname
        1     A1      Alex 
        2     A6      Alex 
        4     A1       Bob 
        5     A9     Chris 
        6     A6     Chris
        

        也许更干净一点……也许?

        【讨论】:

          【解决方案9】:

          根据 Brian Digg 的帖子,这里有两个有用的过滤列表功能:

          #Returns all items in a list that are not contained in toMatch
          #toMatch can be a single item or a list of items
          exclude <- function (theList, toMatch){
            return(setdiff(theList,include(theList,toMatch)))
          }
          
          #Returns all items in a list that ARE contained in toMatch
          #toMatch can be a single item or a list of items
          include <- function (theList, toMatch){
            matches <- unique (grep(paste(toMatch,collapse="|"), 
                                    theList, value=TRUE))
            return(matches)
          }
          

          【讨论】:

            【解决方案10】:

            您尝试过match()charmatch() 函数吗?

            使用示例:

            match(c("A1", "A9", "A6"), myfile$Letter)
            

            【讨论】:

            • match 需要注意的一点是它没有使用模式,它期望完全匹配。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-04-08
            • 1970-01-01
            • 1970-01-01
            • 2016-11-09
            • 1970-01-01
            • 2022-11-01
            • 2012-03-21
            相关资源
            最近更新 更多