【问题标题】:Regex for exluding some words, while matching others用于排除某些单词,同时匹配其他单词的正则表达式
【发布时间】:2021-05-25 19:23:10
【问题描述】:

我正在尝试在 python 中使用正则表达式匹配以下内容(re 模块):

"...milk..."              => matched ['milk']

"...almondmilk..." = no match
"...almond milk..." = no match
"...almond word(s) milk..." => matched ['milk']
"...almondword(s)milk..." => matched ['milk']


"...soymilk..." = no match
"...soy milk..." = no match
"...soy word(s) milk..." => matched ['milk']
"...soyword(s)milk..." => matched ['milk']

我的另一个要求是找到给定字符串中的所有匹配项。所以我使用re.findall()

我使用question 的答案(并查看了许多其他 SO 页面)来构建我的正则表达式:

regx = '^(?!.*(soy|almond))(?=$|.*(milk)).*'

但是当我用一个简单的例子测试它时,我得到了不正确的行为:

>>> food = "is combined with creamy soy and milk. a fruity and refreshing sip of spring, "
>>> re.findall(regx, food)
[]
>>> food = "is combined with creamy milk. a fruity and refreshing sip of spring, "
>>> re.findall(regx, food)
[('', 'milk')]

这两个都应该只返回['milk']。另外,如果我有多个牛奶实例,我只会得到一个结果而不是两个:

>>> food = "is combined with creamy milk. a fruity and refreshing sip of milk, "
>>> re.findall(regx, food)
[('', 'milk')]

我在我的正则表达式中做错了什么,我应该如何调整它来解决这个问题?

【问题讨论】:

  • 也许(?<!soy)(?<!soy )(?<!almond)(?<!almond )milk 对你有用。
  • 我不确定您是否考虑过这一点。那么“......对于杏仁行业。许多牧场主发现牛奶是一种提神饮料。”?那应该匹配吗?如果没有,为什么不呢?
  • @TimRoberts 这是给我还是给 Wiktor 的问题?对于我非常具体的用例,这需要匹配,因为它属于“......杏仁词牛奶......”。其中 word(s) 是任意数量的单词。

标签: python regex


【解决方案1】:

您可以通过匹配排除soymilksoy milkalmondmilkandalmond milk`,并在捕获组中仅捕获牛奶,这将由re.findall返回。

\b(?:soy|almond)\s?milk\b|\b(milk)\b

模式匹配:

  • \b 防止部分匹配的单词边界
  • (?:soy|almond) 搭配大豆或杏仁
  • \s?milk\b 匹配可选的空格字符和牛奶,后跟单词边界
  • |或者
  • \b(milk)\bgroup 1中捕获牛奶,被单词边界包围

您也可以使用[^\S\r\n] 代替\s 来匹配没有换行符的空格,因为后者可以匹配换行符。

Regex demo | Python demo

例如

import re

regx = r"\b(?:soy|almond)\s?milk\b|\b(milk)\b"

food = "is combined with creamy soy and milk. a fruity and refreshing sip of spring, "
print(re.findall(regx, food))

food = "is combined with creamy milk. a fruity and refreshing sip of spring, "
print(re.findall(regx, food))

输出

['milk']
['milk']

另一种选择是使用PyPi regex module

(?<!\b(?:soy|almond)\s*(?:milk)?)\bmilk\b

模式匹配:

  • (?&lt;! 负后视,断言左边的不是
  • \b(?:soy|almond)一个词的边界,匹配大豆或杏仁
  • \s*(?:milk)? 匹配可选的空白字符,然后可选地牛奶
  • ) 近距离观察
  • \bmilk\b在单词边界之间匹配牛奶

Regex demo | Python demo

【讨论】:

  • 这匹配 almondmilk 的空字符串,而不是不匹配 &gt;&gt;&gt; food = "is combined with creamy almondmilk. a fruity and refreshing sip of spring, " &gt;&gt;&gt; re.findall(regx, food) ['']
  • @TayyarR 您可以从最终列表中删除空匹配项,例如 print([m for m in re.findall(regx, food) if m]) 请参阅 ideone.com/YAqX7b
  • 谢谢!每次出现不需要的匹配项(almond for ex)时是否会显示空字符串,或者是否存在其他情况会返回空字符串?这是一个菜鸟问题:有没有办法构建正则表达式,以便列表中只返回 real 匹配项?
  • @TayyarR 这是排除你不想要的东西并捕捉你想要的东西的技术的一部分。例如,您可以使用列表推导来删除空字符串。
  • @TayyarR 如果你可以使用PyPi regex module,你可以使用regex101.com/r/nrnotP/1
【解决方案2】:

This regex 为我工作。

(?:soy|almond)\s?[\w\(\)]+\s?(milk)

或者不接受词中的括号:

(?:soy|almond)\s?\w+\s?(milk)

在 Python 中,应该是这样的:

import re

matches = re.findall(r'(?:soy|almond)\s?[\w\(\)]+\s?(milk)', your_text)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 2016-12-06
    相关资源
    最近更新 更多