仅当没有给定前缀具有任意数量的空格时才匹配单词

Posted

技术标签:

【中文标题】仅当没有给定前缀具有任意数量的空格时才匹配单词【英文标题】: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) 将起作用。 【参考方案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】:

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

    如果文本中有“bar” 如果不是(“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

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

【讨论】:

以上是关于仅当没有给定前缀具有任意数量的空格时才匹配单词的主要内容,如果未能解决你的问题,请参考以下文章

用空格(或任何字符)将文本单元格拆分为任意数量的单词,重复单词

正则表达式总结

正则基础

给定一个单词之间有多个空格的句子。删除多余的空格,使句子在单词之间只有一个空格[重复]

用单个空格替换任意数量的空格[重复]

MongoDB + Mongoose:仅当给定键不存在或具有虚假值时才设置