首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以特殊字符开头或结尾的单词边界会产生意想不到的结果。

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

Stack Overflow用户
提问于 2017-07-17 13:29:36
回答 2查看 2K关注 0票数 10

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

使用python re我可以这样做:

代码语言:javascript
复制
>>> 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}'>

这是可行的,但我希望避免使用搜索模式Sortes,以便在短语test Sortes\index[persons]{Sortes} text上给出一个积极的结果。

代码语言:javascript
复制
>>> re.search(re.escape('Sortes'), match)
<_sre.SRE_Match object; span=(5, 11), match='Sortes'>

所以我使用\b模式,如下所示:

代码语言:javascript
复制
search = r'\b' + re.escape('Sortes\index[persons]{Sortes}') + r'\b'
match = 'test Sortes\index[persons]{Sortes} text'
re.search(search, match)

现在,我没有找到匹配的。

如果搜索模式不包含任何字符[]{},则可以工作。例如:

代码语言:javascript
复制
>>> re.search(r'\b' + re.escape('Sortes\index') + r'\b', 'test Sortes\index test')
<_sre.SRE_Match object; span=(5, 17), match='Sortes\\index'>

另外,如果我移除最后的r'\b',它也能工作:

代码语言:javascript
复制
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}'>

此外,文档还提到了\b

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

因此,我尝试用(\W|$)替换最终的(\W|$)

代码语言:javascript
复制
>>> 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} '>

瞧,它起作用了!这里发生什么事情?我遗漏了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-17 13:37:43

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

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

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

在您的模式中,}\b只匹配}后面的单词char (字母、数字或_)。

使用(\W|$)时,需要显式地使用非字或字符串的结尾。

一种解决方案是自适应字界

代码语言:javascript
复制
re.search(r'(?:(?!\w)|\b(?=\w)){}(?:(?<=\w)\b|(?<!\w))'.format(re.escape('Sortes\index[persons]{Sortes}')), 'test Sortes\index[persons]{Sortes} test')

或相当于:

代码语言:javascript
复制
re.search(r'(?!\B\w){}(?<!\w\B)'.format(re.escape('Sortes\index[persons]{Sortes}')), 'test Sortes\index[persons]{Sortes} test')

在这里,使用了自适应的动态单词边界,这意味着:

  • (?:(?!\w)|\b(?=\w)) (等于(?!\B\w)) -一个左边框,如果下一个字符是一个单词字符,则确保当前位置在单词边界,或者如果下一个字符不是一个单词字符,则不应用上下文限制(注意,如果您想要禁止在左边的一个单词字符,如果下一个字符不是字符,则需要使用(?:\B(?!\w)|\b(?=\w)) )。
  • (?:(?<=\w)\b|(?<!\w)) (等于(?<!\w\B)) --一个右边框,如果前一个字符是一个单词字符,则确保当前位置在单词边界,或者如果前一个字符不是一个单词字符,则不应用上下文限制(注意,如果您想不允许在右边立即使用一个单词char,如果前面的字符不是一个字符,则需要使用(?:(?<=\w)\b|\B(?<!\w)) )。

在这些情况下,您还可以考虑使用基于负面查找的无歧义的单词边界

代码语言:javascript
复制
re.search(r'(?<!\w){}(?!\w)'.format(re.escape('Sortes\index[persons]{Sortes}')), 'test Sortes\index[persons]{Sortes} test')

在这里,如果当前位置左侧有一个单词char,则(?<!\w)负查找将导致匹配失败,如果当前位置右侧有一个单词char,则(?!\w)负查找将导致匹配失败。

与明确的单词边界相比,选择哪一个?自适应字词边界更为宽松,因为后者假定匹配的两端必须没有单词字符,而前者允许在任何上下文中匹配、引导和尾随非单词字符。

注意:进一步定制这些查找模式很容易(例如,只有在模式周围有字母的情况下,才能使匹配失败,使用[^\W\d_]而不是\w,或者如果只允许在空格周围匹配,则使用空白边界 (?<!\S) / (?!\S)查找边界)。

票数 11
EN

Stack Overflow用户

发布于 2017-07-17 13:45:47

我想这就是你遇到的情况:

\b位于\w\W的边界上,但在示例中这是行不通的。'{Sortes}\b'\W\W之间的边界,因为'}'\w的普通集合[a-zA-Z0-9_]不匹配。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45145626

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档