Python 正则表达式中的可选点

Python 正则表达式中的可选点,python,regex,python-2.7,Python,Regex,Python 2.7,假设我想将Mr.和Mr的所有匹配项替换为Mister 我正在使用以下正则表达式:\bMr(\)?\b来匹配Mr.或只匹配Mr。然后,我用这个来做替换 让我困惑的是,它正在用先生取代先生。。为什么要把点保留在最后?看起来它与Mr\.案例不匹配,而只是Mr import re s="a rMr. Nobody Mr. Nobody is Mr Nobody and Mra Nobody." re.sub(r"\bMr(\.)?\b","Mister", s) 返回: 'a rMr. Nobody

假设我想将
Mr.
Mr
的所有匹配项替换为
Mister

我正在使用以下正则表达式:
\bMr(\)?\b
来匹配
Mr.
或只匹配
Mr
。然后,我用这个来做替换

让我困惑的是,它正在用
先生取代
先生。
。为什么要把点
保留在最后?看起来它与
Mr\.
案例不匹配,而只是
Mr

import re
s="a rMr. Nobody Mr. Nobody is Mr Nobody and Mra Nobody."
re.sub(r"\bMr(\.)?\b","Mister", s)
返回:

'a rMr. Nobody Mister. Nobody is Mister Nobody and Mra Nobody.'
我还尝试了以下方法,但也没有成功:

re.sub(r"\b(Mr\.|Mr)\b","Mister", s)
我期望的输出是:

'a rMr. Nobody Mister Nobody is Mister Nobody and Mra Nobody.'
                     ^                              ^
                     no dot            this should be kept as it is
尝试此操作。您需要在
之后删除
\b

输出:
a rMr。没有人先生没有人是先生没有人和Mra没有人。

\bMr(\)?\b
不起作用的原因是
空格之间没有单词边界

有三种不同的位置可以作为单词边界:

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

我认为您希望捕获
'Mr'
,然后是一个
'.
或一个单词边界:

使用中:

>>> import re
>>> re.sub(r"\bMr(?:\.|\b)", "Mister", "a rMr. Nobody Mr. Nobody is Mr Nobody and Mra Nobody.")
'a rMr. Nobody Mister Nobody is Mister Nobody and Mra Nobody.'

@jonsharpe的答案是可行的,但这一个更简单:
\bMr(\.\124;\ b)


我认为在最初的帖子中,
\b
是一些混乱的原因

发件人:

\b在不使用任何字符的情况下,在a 与\w匹配的字符和与\w不匹配的字符 订单)

\w匹配任何字母、数字或下划线

OP希望
\b
与点和它后面的空格之间的边界相匹配。但它没有,因为点与
\w
不匹配。相反,
\b
匹配了“Mr”文本和点之间的边界。这导致圆点没有被捕获,这就是OP所问的问题。这可以在这里看到:

re.sub(r'\bMr[\s\.]', 'Mister ', s)



如果这是Code Golf,我会赢吗?

您正在对可选的“.”字符进行分组。您还可以使用变通方法@hwnd,这是一种很好的方法!我喜欢,谢谢。@fedorqui你想在
foo:Mr:bar
中匹配
Mr
吗?@AvinashRaj
不可能出现在我的字符串中。唯一可能的情况是
mrnobody
,也应该扩展到
Mister
。因此,我们的想法是所有
Mr
Mr.
应该扩展到
Mister
,除非后面出现字母数字字符。很抱歉,我的问题不够清楚:
Mra
必须保持原样,我不希望它被替换为
Mistera
。也就是说,我想要
Mr.
Mr
+word boundary.OP不想在
Mr.hghgh
中匹配
Mr.
,这是一个很好的答案,非常感谢您对我做错了什么、您如何才能正确地做以及为什么这样做的非常深刻的解释。我选择@jornsharpe的答案作为被接受的答案,因为它更直截了当,但肯定会提高投票率。
(?:…)
是为了避免不必要的捕获。但它给出了所需的输出。当然,它确实如此,但这个答案有什么改进?另一个答案显式地使组不被捕获,以稍微减少开销。这个答案中有更少的符号供读者解析。来自Python的禅宗:“可读性很重要。”很好!哪些边缘案例阻止了
?:
?对我来说,
\bMr(\.\124;\ b)
工作得很好。@fedorqui在
Mr
之后有什么需要捕获点或单词边界?@fedorqui
(\.\124;\ b)
也捕获Mr后面的任何内容,因此你可以,例如,在你重新定义句子后重新使用它<代码>?:
使它不会发生。它几乎不会对性能和可读性产生任何影响,但如果您将一个组重复未知的次数,然后需要捕获该重复组后面的一个组,那么它将非常有帮助。使重复组不被捕获意味着您提前知道被捕获组的索引是什么,而不必首先计算它。@NateKerkhofs我想说,它对可读性有很大的影响,特别是在这种情况下,如果它毫无意义的话。编写
\bMr\b\不是更简单吗?
?有趣!请注意,虽然以
Mr开头的字符串不会被当前解决方案替换。这就是单词边界的原因。很好!我是按字面上的例子去做的。我删除了解决方案,留下了问题的解释。@fedorqui-谢谢-这当然是我的本意。␣没有人告诉先生␣␣没有人也就是说,它增加了一个额外的空间。请参见regex101.com/r/dE1yF6/1这项工作,但它会将“Mr”之后的多个空格替换为一个空格。请参阅以避免此问题,您可以使用
re.sub(r'\b(Mr(\)?(\s+))、r'Mister\3',s)
。看见
>>> import re
>>> re.sub(r"\bMr(?:\.|\b)", "Mister", "a rMr. Nobody Mr. Nobody is Mr Nobody and Mra Nobody.")
'a rMr. Nobody Mister Nobody is Mister Nobody and Mra Nobody.'
>>> s="a rMr. Nobody Mr. Nobody is Mr Nobody and Mra Nobody."
>>> re.sub(r'\b(Mr[\.\s]\s*)',r'Mister ',s)
'a rMr. Nobody Mister Nobody is Mister Nobody and Mra Nobody.'
re.sub(r'\bMr[\s\.]', 'Mister ', s)