【问题标题】:Match word only if no given prefix with arbitrary number of spaces仅当没有给定前缀具有任意数量的空格时才匹配单词
【发布时间】:2021-10-30 05:19:56
【问题描述】:

我正在尝试创建一个匹配单词 bar 的正则表达式,除非后面有单词 foo

我发现负向lookbehind 可以处理这个问题,但问题是在foobar 之间有任意数量的字符属于表达式[\s\-/]

不幸的是,负后视不支持任意长度。

所以(?<!foo[\s\-/]*)bar 模式无效。

你知道可以克服这个问题的正则表达式技术吗?

【问题讨论】:

  • 只是要指出:不支持任意前瞻/后视长度通常不是正则表达式限制,而是某些正则表达式实现的限制。例如this 适用于 JavaScript,但基本上没有其他正则表达式实现选择,因此标记您正在使用的正则表达式的特定风格可能会有所帮助
  • @apokryfos 我在 python3 中使用re,它不支持它(显然)。而且我不能真正改变我使用的包,因为这意味着我的代码会发生很多变化......
  • 如果您安装 PyPi 正则表达式模块 (pip install regex) 然后使用 import regex as re,我认为不需要更改任何内容。然后,re.findall(r'(?<!\bfoo\b.*?)\bbar\b', text) 将起作用。

标签: python regex re


【解决方案1】:

一种解决方案是:

import re

c = re.compile(r'^(?!.*foo.*bar).*(bar).*$')

lst = ['bar', 'hi bar', 'foo   bar', 'foobar', 'hiiifoohiiibar']

for i in lst:
    match_obj = c.match(i)
    if match_obj:
        print(match_obj.group(), '|', match_obj.group(1))

输出:

bar | bar
hi bar | bar

DEMO

解释:首先我们检查整个字符串,看看(?!.*foo.*bar)的字符串(先是foo然后是bar)中是否同时存在'foo''bar'。这是一个否定的前瞻断言,如果这对不存在,我们可以继续。

接下来我们确定在bar 之前没有任何foo,我们得到包括bar 在内的所有字符串。我们将它放在一个组中,以便我们可以通过group(1) 检索它。

【讨论】:

  • 这可行,但请注意,它只会捕获组 1 中最后一次出现的 bar。
【解决方案2】:

一种技术是使用 PyPi 正则表达式模块而不是标准的重新模块。当我阅读您的查询时,您似乎想要验证其中包含单词“bar”的任何字符串,除非它前面有单词“foo”以及任意数量的空格和连字符。如果正确,您可以使用:

(?<!foo[\s-]*)bar

意义;以 'foo' 开头并包含 0 次以上的空白字符和/或连字符的否定后视。下面是一些示例代码:

import regex as re
lst = ['foobar', 'foo   -   bar', 'foo- -bar', 'foodbar']
for i in lst:
    if re.search(r'(?<!foo[\s-]*)bar', i):
        print(i)

打印:

foodbar

【讨论】:

    【解决方案3】:

    您将需要这个pip package regex - 它不适用于默认的re

    foo\s*+bar(*SKIP)(*FAIL)|bar
    

    regex101

    解释器中的示例调用:

    >>> import regex
    >>> print(regex.search(r'foo\s*+bar(*SKIP)(*FAIL)|bar', 'fdfdf foo bar fdfdf foo bar bar'))
    <regex.Match object; span=(28, 31), match='bar'>
    

    【讨论】:

    • 或者也匹配问题中的字符,可能是foo[\s/-]*bar(*SKIP)(*FAIL)|bar
    【解决方案4】:

    我的解决方案很简单:测试分为两部分:

    1. 如果文本中有“bar”
    2. 如果不是(“bar”,加上[\s\-/],加上“foo”)

    将其放入代码中:

    import re
    
    data = [
        # Good
        "bar and not foo",
        "bar alone",
    
        # Bad
        "bar - foo",
        "barfoo",
        "bar foo",
        "bar / foo",
    ]
    
    
    for text in data:
        if "bar" in text and not re.match(r"bar[\s\-/]*foo", text):
            print(text)
    

    输出:

    bar and not foo
    bar alone
    

    一般来说,我远离正则表达式,因为它很难理解。我只在必要时使用它。

    【讨论】:

      猜你喜欢
      • 2019-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-19
      • 2011-05-19
      • 1970-01-01
      • 1970-01-01
      • 2020-06-26
      相关资源
      最近更新 更多