【问题标题】:Regex to test if there's a word appeared exactly 2 times正则表达式测试是否有一个单词恰好出现了 2 次
【发布时间】:2021-05-07 09:49:41
【问题描述】:

给定一个字符串,测试是否有一个单词恰好出现了两次

Input Pass
apple banana pineapple No
apple banana apple pineapple Yes
apple banana banana pineapple Yes
apple banana apple pineapple apple No
apple banana apple banana Yes
apple banana banana apple pineapple apple Yes

我尝试了类似的方法但没有用:(

^.*(\b\w+\b)(?:(?!\b\1\b).)*\b\1\b(?:(?!\b\1\b).)*$

有什么建议吗?我正在使用 pcre。

【问题讨论】:

  • 如果有一对两个确切的词和三个其他的确切词怎么办?
  • @JvdV 应该可以通过,只要有一个词恰好出现2次即可
  • @HaoWu 这对我来说似乎是一个非常违反直觉的边缘情况,您的示例数据也没有涵盖。您可能只想在应用程序语言中形成一组单词并在那里进行检查,而不是使用正则表达式。
  • @TimBiegeleisen 抱歉,我在示例输入中添加了边缘情况。
  • 顺便说一句,是PCRE2还是PCRE?

标签: regex pcre


【解决方案1】:

获取下一个单词。如果它恰好包含 2 次,则停止。循环。

^(?*.*?\b(\w+)\b)(?>.*?\b\1\b){2}(?!.*\b\1\b)

Demo

【讨论】:

  • ++ 教我Non atomic Positive Lookahead 的这个新特性,但这是特定于 PCRE2 (PHP > 7.3) 并且 不兼容 Perl b>.
  • ++ 也没听说过。也许我应该为此升级我的 PHP。
【解决方案2】:

使用 PyPi regex 模块,允许动态长度后视:

\b(\w+)\b(?<!\b\1\b.*\b\1\b)(?:(?!\b\1\b).)*?\b\1\b(?!.*\b\1\b)

RegEx Demo

代码:

>>> import regex as re
>>> arr = ["apple banana pineapple", "apple banana apple pineapple", "apple banana banana pineapple",
... "apple banana apple pineapple apple", "apple banana apple banana", "apple banana banana apple pineapple apple"]
>>> reg = re.compile(r'\b(\w+)\b(?<!\b\1\b.*\b\1\b)(?:(?!\b\1\b).)*?\b\1\b(?!.*\b\1\b)')
>>> for i in arr: print (i, '=>', reg.findall(i))
...
apple banana pineapple => []
apple banana apple pineapple => ['apple']
apple banana banana pineapple => ['banana']
apple banana apple pineapple apple => []
apple banana apple banana => ['apple']
apple banana banana apple pineapple apple => ['banana']

正则表达式详细信息:

  • \b(\w+)\b: 匹配一个带有单词边界的单词并在 #1 组中捕获
  • (?&lt;!\b\1\b.*\b\1\b): 动态长度后视断言我们在这个词之前没有同一个词的另一个实例
  • (?:(?!\b\1\b).)*?\b\1\b: 匹配同一个单词的另一个实例,同时确保我们在两次重复之间不匹配同一个单词
  • (?!.*\b\1\b):最后让我们前面没有这个词的其他实例,从而确保只有2个实例

较早的答案:

这个带有负前瞻的正则表达式可能会起作用:

^(?!.*?\b(\w+)\b(?:.*\b\1\b){2}).*?\b(\w+)\b.*\b\2\b

RegEx Demo

正则表达式详细信息:

  • ^:开始
  • (?!: 消极的后视开始
    • .*?:匹配 0 个或多个任意字符
    • \b(\w+)\b:匹配并捕获一个单词 - (?:.*\b\1\b){2}: 如果同一个词至少出现两次
  • ): 消极的后视结束
  • .*?: 匹配 0 个或多个任意字符
  • \b(\w+)\b: 在捕获组#2 中匹配并捕获一个单词
  • .*\b\2\b: 确保同一个词至少再出现一次

【讨论】:

  • @Jvdv:使用regex 模块添加了一个答案,因为它需要可变长度的lookbehind。
  • (?!...) 不是负面展望-提前
  • (?!..) 是负前瞻,但(?&lt;!...) 是负后瞻。
  • OP 使用的是 PHP,而不是 Python
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多