在Python中匹配组

Cur*_*urd 45 python regex

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";
}
Run Code Online (Sandbox Code Playgroud)

翻译成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)
Run Code Online (Sandbox Code Playgroud)

看起来很尴尬(if-else-cascade,匹配对象创建).

Pau*_*McG 38

您可以创建一个返回调用匹配的布尔结果的小类,保留匹配的组以供后续检索:

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 "???"
Run Code Online (Sandbox Code Playgroud)

  • @ΤΖΩΤΖΙΟΥ:我不同意.Beeing对"成千上万的其他人"不考虑引入它的事实感到满意,这简直是愚蠢的.如果我不问"为什么",怎么能确定没有充分的理由不参加这样的课程呢?我没有看到一个,但也许其他人做了并且可以解释它(从而更好地洞察Python的哲学).这是一个很好的例子,这些问题很有效:http://stackoverflow.com/questions/837265/why-is-there-no-operator-in-cc (13认同)
  • @ΤZΩΤZΙΟΥ:我同意;但是,为什么模块中还没有这样的类呢? (3认同)

S.L*_*ott 20

效率较低,但更简单:

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)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

一些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
Run Code Online (Sandbox Code Playgroud)

这几乎不值得一提,除了它有时来自Perl程序员.

  • @ S.Lott:好的,你的解决方案避免了if-else-cascade,但需要花费不必要的匹配(如果m0匹配则不需要m1和m2); 这就是为什么我对这个解决方案并不满意. (4认同)

Xav*_*hot 10

开始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)}')
Run Code Online (Sandbox Code Playgroud)