Python - 能否修改反向引用?

6 投票
4 回答
727 浏览
提问于 2025-04-17 01:11

我刚接触Python,请原谅我的无知。我正在尝试修改正则表达式中的反向引用字符串。

举个例子:

>>>a_string
'fsa fad fdsa dsafasdf u.s.a. U.S.A. u.s.a fdas adfs.f fdsa f.afda'
>>> re.sub(r'(?<=\s)(([a-zA-Z]\.)+[a-zA-Z]\.{0,1})(?=\s)', '<acronym>'+re.sub(r'\.',r'',(r'\1').upper())+'</acronym>', a_string)
'fsa fad fdsa dsafasdf <acronym>u.s.a.</acronym> <acronym>U.S.A.</acronym> <acronym>u.s.a</acronym> fdas adfs.f fdsa f.afda'

我想要的输出是:

'fsa fad fdsa dsafasdf <acronym>USA</acronym> <acronym>USA</acronym> <acronym>USA</acronym> fdas adfs.f fdsa f.afda'

谢谢你的帮助。

4 个回答

2

修改回溯引用”这个说法需要重新表述,因为你似乎对这些概念有些混淆。

一个替换回溯引用是字符串中的一种特殊的字符组合,它告诉正则表达式引擎去引用在匹配操作中获取的某个特定捕获组的值(也叫子匹配)。

当你使用r'\1'.upper()时,你是在尝试把\1这个字符串变成大写,但\1里面没有可以变成大写的字母,所以结果还是\1,这个\1没有改变,依然作为字符串替换模式的一部分。

这就是为什么你不能通过这种方式修改捕获组的值。

所以你必须使用可调用对象作为替换参数(可以参考Ignacio的回答):你需要把匹配对象传递给re.sub,这样才能操作子匹配(当然,你也可以在回溯引用中替换一个或两个字符,比如r'\g<12>'.replace('2','1')来“模糊化”\g<11>的回溯引用,但这样做意义不大)。

3

来自文档

如果repl是一个函数,那么这个函数会被调用来处理每一个不重叠的pattern(模式)出现的地方。这个函数会接收一个匹配对象作为参数,并返回替换的字符串。例如:

你可以查看链接中的示例。

3

正如Ignacio Vazquez-Abrams所建议的,你可以通过传递一个可调用的函数给re.sub()来解决你的问题。我觉得用示例代码来解释最清楚,所以这里有个例子:

import re

s = "fsa fad fdsa dsafasdf u.s.a. U.S.A. u.s.a fdas adfs.f fdsa f.afda"

s_pat = r'(?<=\s)(([a-zA-Z]\.)+[a-zA-Z]\.{0,1})(?=\s)'
pat = re.compile(s_pat)

def add_acronym_tag(match_object):
    s = match_object.group(0)
    s = s.replace('.', '').upper()
    return "<acronym>%s</acronym>" % s

s = re.sub(pat, add_acronym_tag, s)
print s

上面的代码输出:

fsa fad fdsa dsafasdf <acronym>USA</acronym> <acronym>USA</acronym> <acronym>USA</acronym> fdas adfs.f fdsa f.afda

所以你实际上并没有修改回溯引用,因为字符串是不可变的。不过这也没关系:你可以写一个函数来进行任何你想要的处理,然后返回你想要的结果,这就是re.sub()在最终结果中插入的内容。

注意,你可以在你的函数里面使用正则表达式;我只是用了.replace()这个字符串方法,因为你只是想去掉一个字符,实际上并不需要正则表达式的全部功能。

撰写回答