如何在re中替换多个模式

时间:2014-07-21 16:47:40

标签: python regex string

我有以下字符串:

a = 'P/2008 A3 (SOHO)'

我想将其更改为:

a = 'P/2008-A3-SOHO'

尝试解决问题:

第1步:

b = re.sub("\s", "-", a)
print b

输出:

P/2008-A3-(SOHO)

第2步:

c = re.sub("[\(\)]", "", b)
print c

输出:

P/2008-A3-SOHO

我得到了我需要的输出,但有没有更有效的方法呢?我想一步解决它。

3 个答案:

答案 0 :(得分:5)

re.sub不仅接受第二个参数的字符串,还接受一个函数。该函数将匹配对象作为参数获取,函数的返回值用作替换字符串:

>>> re.sub(r"[()\s]", lambda m: '-' if m.group().isspace() else '', a)
'P/2008-A3-SOHO'
顺便说一句,你不需要在角色类(()内逃避)[...]

答案 1 :(得分:2)

您可以使用捕获组从输入中捕获特定字符串。

正则表达式:

^(\S+)\s*(\S+)\s*\(([^)]*)\)$

替换字符串:

\1-\2-\3

DEMO

>>> import re
>>> a = 'P/2008 A3 (SOHO)'
>>> m = re.sub(r'^(\S+)\s*(\S+)\s*\(([^)]*)\)$', r'\1-\2-\3', a)
>>> m
'P/2008-A3-SOHO'

答案 2 :(得分:1)

falsetru提供了一个很好的答案,如何在单个"正则表达式操作中进行多次替换"。

我只想指出,由于可读性和效率的原因,单行并不总是更好。两个正则表达式比具有lambda回调的单个正则表达式更快,我并且认为它们也更具可读性:

>>> import timeit
>>> setup = "import re; a = 'P/2008 A3 (SOHO) P/2008 A3 (SOHO)'"
>>> stmt1 = """re.sub(r"[()\s]", lambda m: '-' if m.group().isspace() else '', a)"""
>>> stmt1 = """r = re.sub(r"[()\s]", lambda m: '-' if m.group().isspace() else '', a)"""
>>> stmt2 = """r = re.sub("\s", "-", a)
... r = re.sub("[\(\)]", "", r)"""
>>> timeit.timeit(setup=setup, stmt=stmt1)
9.311270136909659
>>> timeit.timeit(setup=setup, stmt=stmt2)
7.7278099642134315

当我们事先编译正则表达式(并且,为了正义,定义函数而不是lambda)时,这变得更加明显:

>>> setup = """import re
... a = 'P/2008 A3 (SOHO) P/2008 A3 (SOHO)'
... r1 = re.compile(r"[()\s]")
... r2 = re.compile(r"\s")
... r3 = re.compile(r"[()]")
... def f(m): return '-' if m.group().isspace() else ''
... """
>>> stmt1 = """r = r1.sub(f, a)"""
>>> timeit.timeit(setup=setup, stmt=stmt1)
7.351804295542024
>>> stmt2 = """r = r2.sub("-", a)
... r = r3.sub("", r)"""
>>> timeit.timeit(setup=setup, stmt=stmt2)
4.5631406412521756