正则表达式中的可选点
Posted
技术标签:
【中文标题】正则表达式中的可选点【英文标题】:Optional dot in regex 【发布时间】:2015-01-10 12:36:12 【问题描述】:假设我想将Mr.
和Mr
的所有匹配项替换为Mister
。
我正在使用以下正则表达式:\bMr(\.)?\b
匹配 Mr.
或仅匹配 Mr
。然后,我使用re.sub()
method 进行替换。
让我感到困惑的是,它正在用Mister.
替换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
【问题讨论】:
您正在对可选的 '.' 进行分组。字符。 您也可以使用解决方法\bMr\b\.?
@hwnd 这是个好方法!我喜欢,谢谢。
@fedorqui 你想在foo:Mr:bar
中匹配Mr
吗?
@AvinashRaj :
不太可能出现在我的字符串中。唯一可能的情况是Mr-Nobody
,它也应该扩展为Mister
。因此,想法是所有Mr
或Mr.
都应扩展为Mister
,除非它们后面出现字母数字字符。
【参考方案1】:
我认为您想捕获'Mr'
,后跟'.'
或单词边界:
r"\bMr(?:\.|\b)"
使用中:
>>> 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.'
【讨论】:
不错!哪些边缘情况会阻止?:
?对我来说,\bMr(\.|\b)
工作正常。
@fedorqui 在Mr
之后需要捕获点或单词边界吗?
@fedorqui (\.|\b)
还捕获了 Mr 后面的任何内容,例如,您可以在正则表达式后重用它。 ?:
使它不会发生。它对性能和可读性几乎没有任何影响,但如果您重复一个组未知次数,然后需要在该重复组后面捕获一个组,它会很有帮助。使重复组不捕获意味着您提前知道捕获组的索引是什么,并且不必先计算它。
@NateKerkhofs 我会说它对可读性有重大影响,尤其是在这种情况下毫无意义的情况下。
写\bMr\b\.?
不是更简单吗?【参考方案2】:
re.sub(r"\bMr\.|\bMr\b","Mister", s)
试试这个。你需要在.
之后删除\b
输出:a rMr. Nobody Mister Nobody is Mister Nobody and Mra Nobody.'
\bMr(\.)?\b
不起作用的原因是.
和space
之间没有字边界。
有资格作为单词边界的三个不同位置:
在字符串的第一个字符之前,如果第一个字符是单词字符。 在字符串的最后一个字符之后,如果最后一个字符是单词字符。 字符串中两个字符之间,一个是单词字符,另一个不是单词字符。【讨论】:
对不起,我的问题不够清楚:Mra
必须保持原样,我不希望它被替换为Mistera
。也就是说,我想要Mr.
或Mr
+ 字边界。
OP 不想在 Mr.hghggh
中匹配 Mr.
这是一个很好的答案,非常感谢您对我做错了什么的非常有见地的解释,您如何正确地做以及为什么做错。我选择@jonrsharpe 的答案作为已接受的答案,因为它更直接,但绝对赞成这一点。【参考方案3】:
我认为在原始帖子中\b
是造成一些混乱的原因。
来自regex101:
\b 在 a 之间立即匹配,不消耗任何字符 \w 匹配的字符和 \w 不匹配的字符(在任一 顺序)。
和
\w 匹配任何字母、数字或下划线。
OP 期望 \b
匹配点和它后面的空格之间的边界。但它没有,因为点与\w
不匹配。相反,\b
匹配“先生”文本和点之间的边界。这导致点没有被捕获,这是 OP 所要求的。可以在这里看到:
【讨论】:
有趣!请注意,尽管以Mr
开头的字符串不会被您当前的解决方案替换。这就是词边界\b
的原因。
好点!我是按照这个例子来的。我删除了解决方案并留下了对问题的解释。【参考方案4】:
>>> 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.'
【讨论】:
这可行,但它会将“先生”之后的多个空格替换为一个空格。请参阅regex101.com/r/sC9nG6/4 为避免此问题,您可以改用re.sub(r'\b(Mr(\.)?(\s+))',r'Mister\3',s)
。见regex101.com/r/sC9nG6/5【参考方案5】:
re.sub(r'\bMr[\s\.]', 'Mister ', s)
如果这是 Code Golf,我会赢吗?
【讨论】:
@fedorqui - 谢谢 - 这当然是我的本意。 问题是,这个解决方案将Mr.␣Nobody 转换为Mister␣␣Nobody。也就是说,它增加了一个额外的空间。见 regex101.com/r/dE1yF6/1【参考方案6】:@jonsharpe 的回答有效,但这个有点简单:\bMr(\.|\b)
http://regex101.com/r/sC9nG6/2
【讨论】:
(?:...)
是为了避免不必要的捕获。
但它提供了所需的输出。
当然可以,但是这个答案有什么改进呢?另一个答案明确地使组不捕获以稍微减少开销。
这个答案中有更少的符号供读者解析。来自 Python 之禅:“可读性很重要。”以上是关于正则表达式中的可选点的主要内容,如果未能解决你的问题,请参考以下文章