Я довольно испытан с Perl и Ruby, но в новинку для Python, таким образом, я надеюсь, что кто-то может показать мне Pythonic способ выполнить следующую задачу. Я хочу сравнить несколько строк с несколькими регулярными выражениями и получить группу соответствия. В Ruby это было бы что-то вроде этого:
# Revised to show variance in regex and related action.
data, foo, bar = [], nil, nil
input_lines.each do |line|
if line =~ /Foo(\d+)/
foo = $1.to_i
elsif line =~ /Bar=(.*)$/
bar = $1
elsif bar
data.push(line.to_f)
end
end
Мои попытки в Python оказываются довольно ужасными, потому что группа соответствия возвращается из вызова для соответствования/искания на регулярном выражении, и Python не имеет никакого присвоения в условных выражениях или операторах переключения. Что является Pythonic способ сделать (или думать!) об этой проблеме?
Решение Пола Макгуайра использования промежуточного класса REMatcher
, который выполняет сопоставление, сохраняет группу совпадений и возвращает логическое значение для успеха / неудачи получилось выдать наиболее разборчивый код для этой цели.
В Python есть несколько способов "привязать имя на лету", например, мой старый рецепт "назначить и проверить"; в данном случае я бы, вероятно, выбрал другой такой способ (предполагается, что Python 2. 6, нужны небольшие изменения, если вы работаете со старой версией Python), что-то вроде:
import re
pats_marks = (r'^A:(.*)$', 'FOO'), (r'^B:(.*)$', 'BAR')
for line in lines:
mo, m = next(((mo, m) for p, m in pats_mark for mo in [re.match(p, line)] if mo),
(None, None))
if mo: print '%s: %s' % (m, mo.group(1))
else: print 'NO MATCH: %s' % line
Многие мелкие детали, конечно, могут быть скорректированы (например, я просто выбрал (.*)
, а не (.*?)
в качестве группы соответствия - они эквивалентны, учитывая непосредственно следующий $
, поэтому я выбрал более короткую форму;-) -- Вы могли бы предварительно скомпилировать REs, вычислить вещи иначе, чем кортеж pats_mark
(например, с диктой, индексированной шаблонами RE), и т.д.
Но основные идеи, я думаю, заключаются в том, чтобы сделать структуру управляемой данными, и привязывать объект match к имени на лету с помощью подвыражения for mo in [re. match(p, line)]
, "циклом" по списку из одного элемента (genexps связывает имена только циклом, а не присваиванием - некоторые считают использование этой части спецификаций genexps "хитрым", но я считаю это вполне приемлемой идиомой Python, особенно потому, что она рассматривалась еще во времена разработки listcomps, в некотором смысле "предков" genexps).
ваше регулярное выражение просто принимает все, что находится после третьего символа и далее.
for line in open("file"):
if line.startswith("A:"):
print "FOO #{"+line[2:]+"}"
elif line.startswith("B:"):
print "BAR #{"+line[2:]+"}"
else:
print "No match"
Что-то вроде этого, но красивее:
regexs = [re.compile('...'), ...]
for regex in regexes:
m = regex.match(s)
if m:
print m.groups()
break
else:
print 'No match'