【问题标题】: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。因此,想法是所有MrMr. 都应扩展为Mister,除非它们后面出现字母数字字符。

标签: python regex python-2.7


【解决方案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.'

【讨论】:

【解决方案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 之禅:“可读性很重要。”
猜你喜欢
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多