为什么 re.sub 替换整个模式,而不仅仅是其中的捕获组?

问题描述 投票:0回答:4

re.sub('a(b)','d','abc')
产生
dc
,而不是
adc

为什么

re.sub
替换整个捕获组,而不是仅捕获组'(b)'?

python regex python-3.x replace capturing-group
4个回答
43
投票

因为它应该替换整个出现的模式:

返回通过用替换 repl 替换 string 中最左边不重叠的模式而获得的字符串。

如果仅替换某些子组,则具有多个组的复杂正则表达式将无法工作。有几种可能的解决方案:

  1. 完整指定模式:
    re.sub('ab', 'ad', 'abc')
    - 我最喜欢的,因为它非常易读且明确。
  2. 捕获您想要保留的组,然后在模式中引用它们(请注意,它应该是原始字符串以避免转义):
    re.sub('(a)b', r'\1d', 'abc')
  3. 与上一个选项类似:提供回调函数作为
    repl
    参数,并使其处理
    Match
    对象并返回所需的结果。
  4. 使用lookbehinds/lookaheads,它们不包含在匹配中,但会影响匹配:
    re.sub('(?<=a)b', r'd', 'abxb')
    产生
    adxb
    。该组开头的
    ?<=
    表示“这是一个前瞻”。

5
投票

我知道这并不是严格回答OP问题,但是这个问题很难用谷歌搜索(充斥着解释......)

对于那些像我一样来到这里的人,因为他们想实际用字符串替换不是第一个的捕获组,而不需要对字符串或正则表达式有特殊的了解:

#find offset [start, end] of a captured group within string
r = regex.search(oldText).span(groupNb)
#slice the old string and insert replacementText in the middle 
newText = oldText[:r[0]] + replacementText + oldText[r[1]:]

我知道这是想要的行为,但我仍然不明白为什么 re.sub 无法指定它应该替换的实际捕获组...


4
投票

因为这正是

re.sub()
文档告诉你它应该做的:

  • 模式
    'a(b)'
    表示“匹配'a',带有可选的尾随'b'”。 (它可以单独匹配“a”,但它不可能像您预期的那样单独匹配“b”。如果您是这个意思,请使用非贪婪的
    (a)??b
    )。
  • 替换字符串是“d”
  • 因此,在字符串“abc”上,它匹配所有“ab”并将其替换为“d”,因此结果是“dc”

如果你想要你想要的输出,你需要在

'(a)??'
上进行非贪婪匹配:

>>> re.sub('(a)??b','d','abc')
'dc'

2
投票
import re

pattern = re.compile(r"I am (\d{1,2}) .*", re.IGNORECASE)

text = "i am 32 years old"

if re.match(pattern, text):
    print(
        re.sub(pattern, r"Your are \1 years old.", text, count=1)
    )

如上所述,首先我们编译一个带有不区分大小写标志的正则表达式模式。

然后我们检查文本是否与模式匹配,如果匹配,我们引用正则表达式模式(年龄)中唯一带有组号的组。

© www.soinside.com 2019 - 2024. All rights reserved.