如何排除一组单词但在 qregexp 中包含另一组单词?

How to exclude one set of words but include another in qregexp?

我试图排除一组词,但在 qregexp 表达式中包含另一组词,但我目前在解决这个问题时遇到问题。

以下是我尝试过的一些方法(这个例子包含了所有的单词):

(words|I|want|to|include)(?!the|ones|that|should|not|match)

所以我尝试了这个(没有返回任何结果):

^(words|I|want|to|include)(?:(?!the|ones|that|should|not|match).)*$

我是不是漏掉了什么?

编辑:我需要这样一个不寻常的正则表达式 (include/exclude) 的原因是因为我想搜索一系列文章并过滤其中包含单词但如果它们也包含单词的文章里面有被排除的词。

例如,如果文章 A 是:

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

而文章 B 是:

Vivamus fermentum semper porta.

那么包含 lorem 的正则表达式将过滤文章 A 而不是 B。但是如果 ipsum 是我要排除的词,我不希望文章 A 被过滤。

我考虑过做一个正则表达式来过滤掉我想要的词的文章,然后 运行 第二个正则表达式排除第一组中我不想要的文章,但不幸的是我正在使用的软件不允许我这样做。我只会运行一个正则表达式。

试试这个:

^(?:(?:(?!\b(?:the|ones|that|should|not|match)\b).|))*?\b(?:words|I|want|to|include)\b(?:(?:(?!\b(?:the|ones|that|should|not|match)\b).|))*$

参见 Debuggex Demo(包含匹配和不匹配示例)。

注意:以上假定 QRegExp 支持可变长度先行 - 我还没有验证这一点。

解释:

  1. 所有单词都必须准确无误(例如,包括 "word" 但不包括 "sword" 或 "words"),因此两边都被包裹在 \b 中。
  2. 对于您想包含的单词,重要的是 至少出现一个 至少出现一次 - 仅此而已正在搜索中。
  3. 排除列表中的
  4. None 个词可能出现在 之前或之后 搜索的词,因此需要 "exclusion group" 任一侧。
  5. 排除组是使用一种在 this answer 中有很好解释的方法实现的。
  6. 第一个排除组使用 *? 使其成为非贪婪的,因此它不会消耗整个文本并在找到搜索词后立即停止。
  7. 正则表达式包裹在 ^...$ 中以确保整个字符串是 checked/matched,而不只是其中的一部分。
  8. 在第一个括号后立即使用 ?: 将所有组标记为非捕获组。
  9. 匹配应该不区分大小写,因此正则表达式应该有适当的标志来做到这一点(例如 /i)。

我认为没有必要在一个温和的贪婪量词中。在 锚定否定前瞻 中使用排除的词作为替代词。让我来指导你完成这个。

你说,你有 Lorem ipsum dolor sit amet, consectetur adipiscing elit.,你希望它匹配,因为它包含单词 lorem。正则表达式是 \blorem\bQRegExp.CaseInsensitive 设置为 1),其中 \b 用于强制整个单词匹配。为防止字符串包含单词 ipsum 时的匹配,您需要在字符串的最开头使用前瞻。

^(?!.*\bipsum\b).*\blorem\b

现在,it does not match the string in question.

要添加更多替代项,我们可以使用 alternation operator |, and we can do it like this: ^(?!.*\b(?:words|to|exclude)\b).*\b(?:words|to|include)\b. Note the use of non-capturing groups,它不存储任何捕获的文本,与将匹配文本保存在缓冲区中的捕获组相比,它可能会提高性能。

因此,你得到

^(?!.*\b(?:the|ones|that|should|not|match)\b).*\b(?:words|I|want|to|include)\b

demo

两个备注:

  1. 在演示网站上,必须使用单反斜杠,我在这里将它们加倍以用于 QRegExp
  2. 在 Qt 中,模式中的 . 匹配任何字符,包括换行符。在演示网站上,点与换行符不匹配。如果您需要相同的功能,您可能希望将其替换为 [^\n],但我认为没有必要。
^(?:(?!\b(?:the|ones|that|should|not|match)\b).)*\b(?:words|I|want|to|include)\b(?:(?!\b(?:the|ones|that|should|not|match)\b).)*$

在找到应该 match.See 演示的单词后,您需要向两个部分添加前瞻。

https://regex101.com/r/bK9wF1/3

^(?!.*\b(?:the|ones|that|should|not|match)\b)(?=.*\b(?:words|I|want|to|include)\b).*$

lookaheads 下添加两个条件。参见演示。

https://regex101.com/r/uF4oY4/60

你们太亲密了。原因

^(words|I|want|to|include)(?:(?!the|ones|that|should|not|match).)*$

不起作用是因为它意味着 开始 是我想包含的单词之一,并继续直到结束,而不是我不想包含的词之一。要修复它,您可以简单地更改开始检查以使用正向先行:

^(?=.*(?:words|I|want|to|include))(?:(?!the|ones|that|should|not|match).)*$

现在这意味着确保从开始到某个点,至少有一个词我想包括 然后像在原始正则表达式中一样继续。

要使其更加严格,您可以使用 word boundaries:

^(?=.*\b(?:words|I|want|to|include)\b)(?:(?!\b(?:the|ones|that|should|not|match)\b).)*$

注意这些都是区分大小写的。要更改它,您可以使用 QRegExp::setCaseSensitivity

您似乎需要的简化版本:

^(?:(?!ipsum).)*(?:lorem)(?:(?!ipsum).)*$

Formatted:

^                    # BOS
 (?:
      (?! ipsum )          # Preceding text, but not these words
      . 
 )*
 (?: lorem )          # Text wanted
 (?:
      (?! ipsum )          # Following text, but not these words
      . 
 )*
 $                    # EOS