Матч-группы в 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)
выглядит очень неловко (если-еще-каскад, создание объекта соответствия).
Ответы
Ответ 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]
Это немного неуклюже, но он выполняет свою работу.