Python中的匹配组
有没有办法在Python中访问匹配的组,而不需要明确地创建一个匹配对象(或者有没有其他方法可以让下面的例子看起来更好)?
这里有一个例子,可以帮助你理解我问这个问题的原因:
下面是Perl代码
if ($statement =~ /I love (\w+)/) {
print "He loves $1\n";
}
elsif ($statement =~ /Ich liebe (\w+)/) {
print "Er liebt $1\n";
}
elsif ($statement =~ /Je t\'aime (\w+)/) {
print "Il aime $1\n";
}
翻译成Python后
m = re.search("I love (\w+)", statement)
if m:
print "He loves",m.group(1)
else:
m = re.search("Ich liebe (\w+)", statement)
if m:
print "Er liebt",m.group(1)
else:
m = re.search("Je t'aime (\w+)", statement)
if m:
print "Il aime",m.group(1)
看起来就很别扭(有很多if-else的层层判断,还要创建匹配对象)。
5 个回答
24
从 Python 3.8
开始,引入了 赋值表达式 (PEP 572),也就是 :=
这个符号。现在我们可以把条件值 re.search(pattern, statement)
存到一个变量里(我们叫它 match
),这样就可以先检查它是不是 None
,然后在条件的主体部分再次使用这个变量:
if match := re.search('I love (\w+)', statement):
print(f'He loves {match.group(1)}')
elif match := re.search("Ich liebe (\w+)", statement):
print(f'Er liebt {match.group(1)}')
elif match := re.search("Je t'aime (\w+)", statement):
print(f'Il aime {match.group(1)}')
33
效率稍低,但看起来更简单:
m0 = re.match("I love (\w+)", statement)
m1 = re.match("Ich liebe (\w+)", statement)
m2 = re.match("Je t'aime (\w+)", statement)
if m0:
print("He loves", m0.group(1))
elif m1:
print("Er liebt", m1.group(1))
elif m2:
print("Il aime", m2.group(1))
Perl 代码的问题在于它会隐式地更新一些隐藏的变量。这在 Python 中很难实现,因为你需要一个赋值语句才能真正更新任何变量。
这个版本重复的部分少(效率也更高):
pats = [
("I love (\w+)", "He Loves {0}" ),
("Ich liebe (\w+)", "Er Liebe {0}" ),
("Je t'aime (\w+)", "Il aime {0}")
]
for p1, p3 in pats:
m = re.match(p1, statement)
if m:
print(p3.format(m.group(1)))
break
有些 Perl 程序员喜欢的一个小变种:
pats = {
"I love (\w+)" : "He Loves {0}",
"Ich liebe (\w+)" : "Er Liebe {0}",
"Je t'aime (\w+)" : "Il aime {0}",
}
for p1 in pats:
m = re.match(p1, statement)
if m:
print(pats[p1].format(m.group(1)))
break
这几乎不值得一提,不过有时候 Perl 程序员会提到。
76
你可以创建一个小类,这个类可以返回调用匹配函数的结果,并且还可以保存匹配到的内容,以便后续使用:
import re
class REMatcher(object):
def __init__(self, matchstring):
self.matchstring = matchstring
def match(self,regexp):
self.rematch = re.match(regexp, self.matchstring)
return bool(self.rematch)
def group(self,i):
return self.rematch.group(i)
for statement in ("I love Mary",
"Ich liebe Margot",
"Je t'aime Marie",
"Te amo Maria"):
m = REMatcher(statement)
if m.match(r"I love (\w+)"):
print "He loves",m.group(1)
elif m.match(r"Ich liebe (\w+)"):
print "Er liebt",m.group(1)
elif m.match(r"Je t'aime (\w+)"):
print "Il aime",m.group(1)
else:
print "???"
更新一下,针对Python 3的打印方式和Python 3.8的新特性,现在不需要再用REMatcher这个类了:
import re
for statement in ("I love Mary",
"Ich liebe Margot",
"Je t'aime Marie",
"Te amo Maria"):
if m := re.match(r"I love (\w+)", statement):
print("He loves", m.group(1))
elif m := re.match(r"Ich liebe (\w+)", statement):
print("Er liebt", m.group(1))
elif m := re.match(r"Je t'aime (\w+)", statement):
print("Il aime", m.group(1))
else:
print()