Python сравнивает строку с несколькими регулярными выражениями - PullRequest
6 голосов
/ 14 апреля 2010

У меня довольно большой опыт работы с 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 не имеет присваивания в условных выражениях или операторах switch. Что Pythonic способ сделать (или думать!) Об этой проблеме?

Ответы [ 4 ]

1 голос
/ 14 апреля 2010

Есть несколько способов «связать имя на лету» в 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

Конечно, можно изменить многие второстепенные детали (например, я просто выбрал (.*) вместо (.*?) в качестве соответствующей группы - они эквивалентны сразу после $, поэтому я выбрал более короткую) form ;-) - вы могли бы предварительно скомпилировать RE, выделить вещи иначе, чем кортеж pats_mark (например, с помощью dict, проиндексированного шаблонами RE) и т. д.

Но существенные идеи, я думаю, состоят в том, чтобы сделать структуру управляемой данными и связать объект сопоставления с именем на лету с помощью подвыражения for mo in [re.match(p, line)], «цикла» над списком из одного элемента ( genexps связывает имена только по циклу, а не по присваиванию - некоторые считают использование этой части спецификаций genexps «хитрым», но я считаю это вполне приемлемой идиомой Python, особенно, поскольку она была рассмотрена в то время, когда списочные списки, в некотором смысле, создавались "предками" genexps).

1 голос
/ 14 апреля 2010

Как то так, но красивее:

regexs = [re.compile('...'), ...]

for regex in regexes:
  m = regex.match(s)
  if m:
    print m.groups()
    break
else:
  print 'No match'
0 голосов
/ 27 апреля 2010

Решение Пола Макгуайра об использовании промежуточного класса REMatcher, который выполняет сопоставление, сохраняет группу совпадений и возвращает логическое значение для успеха / неудачи, получившее наиболее читаемый код для этой цели.

0 голосов
/ 14 апреля 2010

ваше регулярное выражение просто берет все, что есть после 3-го символа и далее.

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"
...