用re.sub替换命名的捕获组

时间:2014-12-23 21:56:54

标签: python regex substitution

我想替换字符串中匹配的重新模式的文本,并且可以使用re.sub()执行此操作。如果我在调用中将一个函数作为repl参数传递,它可以根据需要运行,如下所示:

from __future__ import print_function
import re

pattern = r'(?P<text>.*?)(?:<(?P<tag>\w+)>(?P<content>.*)</(?P=tag)>|$)'

my_str = "Here's some <first>sample stuff</first> in the " \
            "<second>middle</second> of some other text."

def replace(m):
    return ''.join(map(lambda v: v if v else '',
                        map(m.group, ('text', 'content'))))

cleaned = re.sub(pattern, replace, my_str)
print('cleaned: {!r}'.format(cleaned))

输出:

cleaned: "Here's some sample stuff in the middle of some other text."

然而,从文档来看,听起来我应该能够通过传递一个替换字符串来获得相同的结果,该字符串中包含对其中命名组的引用。但是,我这样做的尝试不起作用,因为有时一个组是不匹配的,返回的值是None(而不是空字符串'')。

cleaned = re.sub(pattern, r'\g<text>\g<content>', my_str)
print('cleaned: {!r}'.format(cleaned))

输出:

Traceback (most recent call last):
  File "test_resub.py", line 21, in <module>
    cleaned = re.sub(pattern, r'\g<text>\g<content>', my_str)
  File "C:\Python\lib\re.py", line 151, in sub
    return _compile(pattern, flags).sub(repl, string, count)
  File "C:\Python\lib\re.py", line 278, in filter
    return sre_parse.expand_template(template, match)
  File "C:\Python\lib\sre_parse.py", line 802, in expand_template
    raise error, "unmatched group"
sre_constants.error: unmatched group

我做错了什么或不理解?

2 个答案:

答案 0 :(得分:2)

def repl(matchobj):
    if matchobj.group(3):
        return matchobj.group(1)+matchobj.group(3)
    else:
        return matchobj.group(1)

my_str = "Here's some <first>sample stuff</first> in the " \
        "<second>middle</second> of some other text."

pattern = r'(?P<text>.*?)(?:<(?P<tag>\w+)>(?P<content>.*)</(?P=tag)>|$)'
print re.sub(pattern, repl, my_str)

您可以使用re.sub的通话功能。

编辑: cleaned = re.sub(pattern, r'\g<text>\g<content>', my_str)这不会起作用,因为字符串的最后一位匹配,即of some other text.已定义\g<text>但没有\g<content>,因为没有内容。但是你仍然会问{{ 1}}来做它。因此它会生成错误。如果你使用字符串re.sub,那么你的"Here's some <first>sample stuff</first> in the <second>middle</second>"将起作用print re.sub(pattern,r"\g<text>\g<content>", my_str)一直在这里定义。

答案 1 :(得分:1)

如果我理解正确,您希望删除< >包含之间的所有内容:

>>> import re

>>> my_str = "Here's some <first>sample stuff</first> in the <second>middle</second> of some other text."

>>> print re.sub(r'<.*?>', '', my_str)

Here's some sample stuff in the middle of some other text.

在某种程度上解释这里发生的事情...... r'<.*?>'

<找到第一个<

.然后接受任何字符

*多次接受任何字符

?将结果限制在尽可能短的时间内,如果没有这个,它会一直持续到最后>而不是第一个可用的

>找到结束点>

然后,用任何东西替换这两点之间的所有东西。