【问题标题】:Regex match if there is only one match from a number of choices in a string如果字符串中的多个选项中只有一个匹配项,则正则表达式匹配
【发布时间】:2020-06-16 18:48:23
【问题描述】:

是否有一种模式可以从字符串中的多个选项中查找是否只有一个匹配项?

假设我们有以下潜在匹配列表:

`foo|bar|baz`

我们有字符串:

`Foo bar, Cambaz!` // shoud not match due to multiple findings
`My bar, good!` // shoud match for `bar`
`My friend, Cambaz!` // shoud match for baz

不区分大小写。

【问题讨论】:

  • 请展示你的尝试
  • @anubhava 老实说,我不知道! :))

标签: regex pcre


【解决方案1】:

使用

(?i)^(?:(?!foo|bar|baz).)*\K(?:foo|bar|baz)(?!.*(?:foo|bar|baz))

proof

匹配直到第一个匹配项 (^(?:(?!foo|bar|baz).)*) 之前与任何替代项都不匹配的一些文本,省略匹配的文本 (\K),匹配列表中的单词 ((?:foo|bar|baz)),然后检查那里在文本后面的列表中没有单词 ((?!.*(?:foo|bar|baz)))。

(?i) - 不区分大小写。

带有子程序的缩短版

(?i)^(?:(?!(foo|bar|baz)).)*\K\g<1>(?!.*\g<1>)

another proof

\g&lt;1&gt; 代表(foo|bar|baz) 模式。

【讨论】:

  • 你的最新版本也很漂亮,因为我们不必重复我们正在寻找的字符串。不幸的是,@anubhava 更快。
【解决方案2】:

你可以使用这个 PCRE 正则表达式:

^(?>.*?(foo|bar|baz)){2}.*(*SKIP)(*F)|(?1)

RegEx Demo

  • (*F)(*FAIL) 动词的行为类似于失败的否定断言,是 (?!) 的同义词
  • (*SKIP) 定义了一个点,当子模式稍后失败时,正则表达式引擎不允许回溯。
  • (*SKIP)(*FAIL) 技巧的想法是使用您想要避免的字符,并且这些字符不能成为匹配结果的一部分。
  • (?1):递归第一个子模式

【讨论】:

  • 你是个天才!我猜数字 2 应该是 x-1...
  • @SorinGFS:为避免重复使用:^(?&gt;.*?(foo|bar|baz)){2}.*(*SKIP)(*F)|\g&lt;1&gt;
  • 不错!为什么不将其添加到答案中?
【解决方案3】:

您也可以使用(*COMMIT) 在之后的子模式(此处为前瞻)失败时中止进一步的研究:

(foo|bar|baz)(*COMMIT)(?!.*(?1))

demo

【讨论】:

  • 是的,非常好,到目前为止最短的,由于它的工作方式,它可能是最快的。谢谢!
猜你喜欢
  • 1970-01-01
  • 2019-09-10
  • 1970-01-01
  • 2015-09-02
  • 1970-01-01
  • 1970-01-01
  • 2019-08-17
  • 2021-12-27
  • 1970-01-01
相关资源
最近更新 更多