【问题标题】:R grep whole words separated by special charactersR grep 由特殊字符分隔的整个单词
【发布时间】:2012-10-14 18:34:11
【问题描述】:

假设有一个"foo""foo|baz|bar" 形式的序列向量(一个单词或多个单词,由"|" 等特殊字符分隔),我们也给定了一个单词,我们想找到它有一个整个单词匹配的向量的哪些项目。

例如,单词"foo""foo|baz|bar" 中有一个完整匹配,但在"foobaz|bar""bazfoo" 中没有一个完整匹配。

首先我尝试使用"\\b" 来指示整个单词的开始或结束边缘并且它成功地工作:

grep("\\bfoo\\b", "foo")         # match
grep("\\bfoo\\b", "foobaz|bar")  # mismatch    
grep("\\bfoo\\b", "bazfoo")      # mismatch

然后我尝试添加"|"作为两端的另一个可能的分隔符,并使用[]将其与"\\b"分组:

grep("[|\\b]foo[|\\b]", "foo|baz|bar")  # mismatch!
grep("[|\\b]foo[|\\b]", "foo")          # mismatch!

后来我发现\\b不是字符串的startend的指示符,而是整个单词的开始或结束(这么多字符,如空格和,|-^.不是数字和下划线 _ 分隔整个单词)。所以"[|\\b]foo[|\\b]" 匹配所有这些字符串:"foo", "foo|bar|baz", "foo-bar", "baz foo|bar" 但不匹配"foo_bar""foo2"

但我的问题仍然存在:为什么 "[|\\b]foo[|\\b]" 模式无法与 "foo" 匹配?

【问题讨论】:

  • 我很难选择正确的答案,因为它们中的大多数都非常完美!

标签: r regex


【解决方案1】:

你可以使用strplit:

> "foo" %in% unlist(strsplit("foo|baz|bar", split = "|", fixed = TRUE))
[1] TRUE

你可以矢量化:

> z <- c("foo|baz|bar", "foobaz|bar", "bazfoo")
> x <- c("foo", "foot")
> sapply(strsplit(z, split = "|", fixed = TRUE), function(x,y)y %in% x, x)
      [,1]  [,2]  [,3]
[1,]  TRUE FALSE FALSE
[2,] FALSE FALSE FALSE

【讨论】:

  • 谢谢,但我更想知道为什么 grep("[|\\b]foo[|\\b]", "foo") 不匹配?
  • 因为你需要转义|。出于同样的原因,我选择在strsplit 中使用fixed = TRUE
  • 如果我在寻找 only 的“|”作为分隔符,“\\b”不是一个好的选择,所以你的答案似乎更适合这种情况
  • 它在编程上也很友好:如您所见,创建正则表达式模式不需要难看的粘贴。
  • 谢谢弗洛德尔。你的答案很完美。我希望可以为这个问题选择正确的 3 个答案 - 我什至尝试过!
【解决方案2】:

\b 匹配以下位置

  1. 如果第一个字符是单词字符,则在字符串的第一个字符之前。
  2. 在字符串的最后一个字符之后,如果最后一个字符是单词字符。
  3. 字符串中两个字符之间,一个是单词字符,另一个不是单词字符。 (单词字符为 a-zA-Z1-9_)

自从 |代表正则表达式中的交替运算符,您将不得不对其进行转义。

所以正则表达式 \bfoo\b 将匹配 foo|bar 中的 foo 因为 |是一个非单词字符。无需使用字符集[\b\|]

编辑:正如 flodel 所指出的,字符集中的 \b 下面表示退格字符。所以它会匹配 |在 [\b\|] 内而不是单词边界内。

【讨论】:

    【解决方案3】:

    由于|在正则表达式中有特殊含义,需要转义,即使用\\|

    ptn <- "\\bfoo[\\|\\b]"
    
    grep(ptn, "foo|baz|bar") 
    [1] 1
    
    grep(ptn, "foo")          
    integer(0)
    

    【讨论】:

    • 感谢您的精彩评论。我发现即使是 "\\bfoo\\b" 也能达到我的目的。您认为需要完善您的答案吗?
    • @AliSharfi 如果您想完善我的答案,请继续。我相信我已经回答了您发布的问题。
    • 这里有一些有趣的东西:grep("afooa", "afooa") 给出了匹配。 grep("[a]foo[a]", "afooa") 也是如此。 grep("\\bfoo\\b", "foo") 也是如此,但grep("[\\b]foo[\\b]", "foo") 不是。有什么想法吗?
    • 我在这里找到了我的问题的答案:regular-expressions.info/reference.html在字符类中,\b 是退格字符。。所以这不是一个好方法。
    【解决方案4】:

    这也可以:

    gregexpr("foo|", "foo|baz|bar", fixed = TRUE)[[c(1, 1)]] > 0
    gregexpr("foo|", "foobaz|bar", fixed = TRUE)[[c(1, 1)]] > 0    
    gregexpr("foo|", "bazfoo", fixed = TRUE)[[c(1, 1)]] > 0 
    

    这种方法的不同之处在于您可以利用您提供的间距选项gregexpr 来查找由两个单词组成的单词:

    gregexpr("foo|", "baz foo|", fixed = TRUE)[[c(1, 1)]] > 0 
    gregexpr("  foo|", "baz foo|", fixed = TRUE)[[c(1, 1)]] > 0 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多