4

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

以下是我尝试过的一些事情(这个例子包括了所有的单词):

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

所以我尝试了这个(它什么也没返回):

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

我错过了什么吗?

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

例如,如果文章 A 是:

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

B条是:

Vivamus fermentum semper porta.

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

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

4

5 回答 5

4

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

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

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

现在,它与有问题的字符串不匹配

要添加更多备选方案,我们可以使用交替运算符|,我们可以这样做^(?!.*\\b(?:words|to|exclude)\\b).*\\b(?:words|to|include)\\b:请注意使用非捕获组,它不存储任何捕获的文本,并且与将匹配文本保存在缓冲区中的捕获组相比可能会提高性能。

因此,你得到

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

演示

两个备注:

  1. 在演示网站上,必须使用单反斜杠,我在这里将它们加倍以用于QRegExp.
  2. 在 Qt.中,模式匹配任何字符,包括换行符。在演示网站上,点与换行符不匹配。如果您需要相同的功能,您可能想要替换它[^\n],但我认为没有必要。
于 2015-08-17T23:45:13.650 回答
2

你是如此接近。原因

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

不起作用是因为这意味着我想要包含的单词之一开始,然后一直持续到最后,这不是我不想包含的单词之一。要修复它,您可以简单地将开始检查更改为使用正向前瞻:

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

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

为了使其更加严格,您可以使用单词边界

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

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

于 2015-08-18T08:28:41.893 回答
2
^(?:(?!\b(?:the|ones|that|should|not|match)\b).)*\b(?:words|I|want|to|include)\b(?:(?!\b(?:the|ones|that|should|not|match)\b).)*$

在找到应该匹配的单词后,您需要向这两个部分添加前瞻。参见演示。

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

或者

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

lookaheads在.See 演示下添加这两个条件。

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

于 2015-08-18T04:56:21.473 回答
1

尝试这个:

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

正则表达式可视化

请参阅Debuggex 演示(带有匹配和不匹配示例)。

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

解释:

  1. 所有单词都必须准确(例如,包括“word”,但不包括“sword”或“words”),因此要包含在\b任一侧。
  2. 对于您想要包含的单词,重要的是至少其中一个至少出现一次- 这就是正在搜索的所有内容。
  3. 排除列表中的任何单词都不能出现在搜索单词之前或之后,因此需要在其两侧都有一个“排除组”。
  4. 排除组是使用此答案中很好解释的方法实现的。
  5. 第一个排除组用于*?使其不贪婪,因此它不会消耗整个文本并在找到搜索的单词后立即停止。
  6. 正则表达式包含在^...$中,以确保检查/匹配整个字符串,而不仅仅是其中的一部分。
  7. ?:通过在第一个括号后立即使用,将所有组标记为非捕获组。
  8. 匹配应该不区分大小写,因此正则表达式应该有适当的标志来执行此操作(例如/i)。
于 2015-08-17T23:09:23.113 回答
0

您似乎需要的简化版本:

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

格式化:

^                    # BOS
 (?:
      (?! ipsum )          # Preceding text, but not these words
      . 
 )*
 (?: lorem )          # Text wanted
 (?:
      (?! ipsum )          # Following text, but not these words
      . 
 )*
 $                    # EOS
于 2015-08-18T15:53:07.770 回答