以特殊字符开头或结尾的单词的单词边界会产生意想不到的结果

Ste*_*aer 7 python regex

假设我想匹配短语Sortes\index[persons]{Sortes}中短语的存在test Sortes\index[persons]{Sortes} text

使用 pythonre我可以做到这一点:

>>> search = re.escape('Sortes\index[persons]{Sortes}')
>>> match = 'test Sortes\index[persons]{Sortes} text'
>>> re.search(search, match)
<_sre.SRE_Match object; span=(5, 34), match='Sortes\\index[persons]{Sortes}'>
Run Code Online (Sandbox Code Playgroud)

这有效,但我想避免搜索模式Sortes对短语给出肯定的结果test Sortes\index[persons]{Sortes} text

>>> re.search(re.escape('Sortes'), match)
<_sre.SRE_Match object; span=(5, 11), match='Sortes'>
Run Code Online (Sandbox Code Playgroud)

所以我使用\b模式,像这样:

search = r'\b' + re.escape('Sortes\index[persons]{Sortes}') + r'\b'
match = 'test Sortes\index[persons]{Sortes} text'
re.search(search, match)
Run Code Online (Sandbox Code Playgroud)

现在,我没有得到匹配。

如果搜索模式不包含任何字符[]{},则它有效。例如:

>>> re.search(r'\b' + re.escape('Sortes\index') + r'\b', 'test Sortes\index test')
<_sre.SRE_Match object; span=(5, 17), match='Sortes\\index'>
Run Code Online (Sandbox Code Playgroud)

另外,如果我删除 final r'\b',它也可以工作:

re.search(r'\b' + re.escape('Sortes\index[persons]{Sortes}'), 'test Sortes\index[persons]{Sortes} test')
<_sre.SRE_Match object; span=(5, 34), match='Sortes\\index[persons]{Sortes}'>
Run Code Online (Sandbox Code Playgroud)

此外,文档\b

请注意,形式上,\b 被定义为 \w 和 \W 字符之间(或反之亦然),或 \w 和字符串开头/结尾之间的边界。

所以,我想替换最后\b(\W|$)

>>> re.search(r'\b' + re.escape('Sortes\index[persons]{Sortes}') + '(\W|$)', 'test Sortes\index[persons]{Sortes} test')
<_sre.SRE_Match object; span=(5, 35), match='Sortes\\index[persons]{Sortes} '>
Run Code Online (Sandbox Code Playgroud)

瞧,它有效!这里发生了什么?我错过了什么?

Wik*_*żew 7

查看单词边界匹配的内容:

词边界可以出现在以下三个位置之一:

  • 在字符串中的第一个字符之前,如果第一个字符是单词字符。
  • 在字符串的最后一个字符之后,如果最后一个字符是单词字符。
  • 在字符串中的两个字符之间,其中一个是单词字符,另一个不是单词字符。

在您的模式中,}\b只有在}(字母、数字或_)之后有一个单词 char 时才匹配。

当您使用时,(\W|$)您需要明确地使用非单词或字符串结尾。

在这些情况下,我总是建议基于负面环视的明确词边界:

re.search(r'(?<!\w){}(?!\w)'.format(re.escape('Sortes\index[persons]{Sortes}')), 'test Sortes\index[persons]{Sortes} test')
Run Code Online (Sandbox Code Playgroud)

在这里,(?<!\w)如果当前位置的左边有一个单词 char ,则负向后视将失败匹配,如果当前位置的右边有一个单词 char,则(?!\w)负向前瞻将匹配失败。

实际上,进一步自定义这些环视模式很容易(例如,仅当模式周围有字母时才使匹配失败,使用[^\W\d_]代替\w,或者如果您只允许在空格周围进行匹配,则使用(?<!\S)/(?!\S)环视边界)。