Подтвердить что ты не робот

Матч-группы в 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)

выглядит очень неловко (если-еще-каскад, создание объекта соответствия).

4b9b3361

Ответ 1

Вы можете создать небольшой класс, который возвращает логический результат вызова match и сохраняет соответствующие группы для последующего поиска:

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()

Ответ 2

Менее эффективный, но более простой вид:

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.

Ответ 3

это не регулярное выражение.

alist={"I love ":""He loves"","Je t'aime ":"Il aime","Ich liebe ":"Er liebt"}
for k in alist.keys():
    if k in statement:
       print alist[k],statement.split(k)[1:]

Ответ 4

Начиная с Python 3.8 и введением выражений присваивания (PEP 572) (:= оператор), теперь мы можем re.search(pattern, statement) значение условия 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)}')

Ответ 5

Вы можете создать вспомогательную функцию:

def re_match_group(pattern, str, out_groups):
    del out_groups[:]
    result = re.match(pattern, str)
    if result:
        out_groups[:len(result.groups())] = result.groups()
    return result

И затем используйте его следующим образом:

groups = []
if re_match_group("I love (\w+)", statement, groups):
    print "He loves", groups[0]
elif re_match_group("Ich liebe (\w+)", statement, groups):
    print "Er liebt", groups[0]
elif re_match_group("Je t'aime (\w+)", statement, groups):
    print "Il aime", groups[0]

Это немного неуклюже, но он выполняет свою работу.