【问题标题】:Regex optional character preceded by Negative Lookback in R正则表达式可选字符前面是 R 中的负回溯
【发布时间】:2018-06-28 16:17:12
【问题描述】:

假设我有一组字符串:

test <- c('MTB', 'NOT MTB', 'TB', 'NOT TB')

我想编写一个正则表达式来严格匹配“TB”或“MTB”(例如,表达式“M?TB”),当它前面没有短语“NOT”(包括空格)时。

因此,我的预期结果是

TRUE FALSE TRUE FALSE

到目前为止,我已经尝试了几种变体

grepl("(?<!NOT )M?TB", test, perl = T)

TRUE TRUE TRUE FALSE

不成功。如您所见,短语“NOT MTB”符合我的正则表达式的条件。

似乎包括可选字符“M?”似乎让 R 认为消极的后视也是可选的。我一直在研究使用括号对模式进行分组,例如

grepl("(?<!NOT )(M?TB)")

TRUE TRUE TRUE FALSE

这也未能排除短语“NOT MTB”。诚然,我不清楚括号在正则表达式中是如何工作的,甚至不清楚“分组”在这种情况下的含义。我很难找到与如何对正则表达式的不同部分进行分组、要求和“可选”相关的问题,以便我可以匹配一个短语以可选字符开头并以否定回溯开头 em>。写这样的表达式的正确方法是什么?

【问题讨论】:

  • 为什么不简单地使用^MTB|TB' for regex ?`表示要匹配的单个字符。这不会匹配 NOT MTB 我也相信。
  • 请澄清 2 件事:1) 你能拥有你想要获得的 THIS MTB 值吗? 2)如果NOTTB之间有两个或多个空格,需要处理吗?
  • 我希望我的例子没有分散注意力。问题是编写一个匹配“M?TB”的正则表达式和负回溯的附加标准“(?

标签: r regex regex-lookarounds grepl


【解决方案1】:

我们可以使用开头 (^) 和结尾 ($) 来匹配这些单词

grepl("^M?TB$", test)
#[1]  TRUE FALSE  TRUE FALSE

如果在 cmets 中提到了 @Wiktor Stribiżew 等其他字符串,那么一种选择是

test1 <- c(test, "THIS MTB")
!grepl("\\bNOT M?TB\\b", test1) & grepl("\\bM?TB\\b", test1)
#[1]  TRUE FALSE  TRUE FALSE  TRUE

【讨论】:

  • 我认为在"NOT M?TB" 中也使用单词边界是有意义的。另一种选择是在消费部分使用带有贪心点和"\\bM?TB\\b" 的负前瞻检查(在开始时锚定),但它已经是PCRE 正则表达式(perl=TRUE
  • @WiktorStribiżew 谢谢,你是正则表达式之神,我不会和你争论 :=)
【解决方案2】:
test = c("MTB", "NOT MTB", "TB", "NOT TB", "THIS TB", "THIS NOT TB")

grepl("\\b(?<!NOT\\s)M?TB\\b",test,perl = TRUE)

[1]  TRUE FALSE  TRUE FALSE  TRUE FALSE

【讨论】:

  • 嗨@Onyambu。您的建议似乎适用于我的示例,并且似乎正是我想要的。您能否进一步解释前导和尾随“\\b”添加的目的?包括它们会使我的陈述起作用,但我不明白为什么。
  • @G.Vece \\b 匹配单词的边界。确保模式只匹配有边界的单词,而不匹配没有边界的单词
【解决方案3】:

关于问题的意图存在一些问题,但这里有一些代码可以根据需要尝试。

补充:海报澄清 #2 和 #3 符合所寻找的路线。

1) 这可以不用像这样的正则表达式来完成:

test %in% c("TB", "MTB")
## [1]  TRUE FALSE  TRUE FALSE

2) 如果问题不在于完全匹配,则将匹配返回给 M?TB,但不匹配 NOT M?TB:

grepl("M?TB", test) & !grepl("NOT M?TB",test)
## [1]  TRUE FALSE  TRUE FALSE

3) 另一种选择是将 NOT M?TB 替换为 X,然后在 M?TB 上使用 grepl:

grepl("M?TB", sub("NOT M?TB", "X", test))
## [1]  TRUE FALSE  TRUE FALSE

【讨论】:

  • 你确定吗?如果THIS MTB 也应该返回怎么办?
  • 恰恰相反。整个问题是关于在TBMTB 之前检查NOT
  • 感谢您的回复。 #1 回答了一个不同的问题,因为我故意没有指定我正在寻找完全匹配。我正在寻找与“M?TB”匹配的正则表达式解决方案,同时排除“NOT M?TB”,而不管附加的尾随或前导文本。 #2当然是一个解决方案,实际上是我目前正在使用的,但我真的很想更好地学习正则表达式,这似乎是一个很好的负面回顾的案例,同样适用于#3
猜你喜欢
  • 1970-01-01
  • 2012-12-06
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-26
相关资源
最近更新 更多