PCRE 匹配单词但排除匹配单词内或与匹配单词相关的单词列表

PCRE match when words but exclude a list of words within or in relation to matching words

我正在尝试使用 PCRE 正则表达式来匹配以下单词列表:

  1. 牛奶
  2. 鸡蛋

在以下字符串中:

milk, goatmilk, goat milk, cow milk, watch out for ( milk, eggs), egg, cornstarch
milk. goatmilk. goat milk. cow milk. watch out for ( milk, eggs). egg. cornstarch
milk goatmilk goat milk cow milk watch out for ( milk, eggs). egg cornstarch

这将是一个简单的练习,但遗憾的是它无法匹配以下任何单词:

在上述情况下,字符串应该匹配,因为单词:

但如果字符串不包含任何这些词则不应匹配,即:

sugar, wheat, goatmilk, goat milk, cornstarch

我已经尝试应用这些但没有任何成功:

我从上述资源中得到的最接近的正则表达式是:

\b(?!(?:goatmilk|goat\smilk))(egg|milk)\b

这仍然会匹配所有单词 milk,更糟糕的是,由于单词边界,它会跳过单词 eggs。如果我删除 boundry 这个词,它也会匹配 goatmilk..

我已经想到了使用两个正则表达式的可能性,一个用于匹配所有单词,另一个用于检查匹配的单词是否有排除的单词。然而;如果不是山羊和牛奶之间的 space,这将非常有效,因为山羊部分不在比赛中。

如果没有这样做的选项,我将使用 PHP 在 space 上展开,遍历数组,如果找到匹配项,将检查以前的索引值以查看该组合是否包含要排除的词以缓解 space 问题。然而;我宁愿不使用它,因为我认为这个选项非常丑陋:(

如果你必须避免 returning milk 这是 goatmilkgoat milk 的一部分,你可以使用 (*SKIP)(*FAIL) regex:

\bgoat\s*milk\b(*SKIP)(*FAIL)|\b(?:eggs?|milk)\b

regex demo

\bgoat\s*milk\b(*SKIP)(*FAIL) 分支将匹配 goatmilkgoat milk 并将丢弃由于这 2 个 PCRE 动词而导致的匹配。 \b(?:eggs?|milk)\b 分支将 return 其他 eggeggsmilk 作为全词匹配。