2010-04-13 4 views
6

Jestem dość doświadczony z Perlem i Ruby, ale jest nowy w Pythonie, więc mam nadzieję, że ktoś może mi pokazać Pythoniczny sposób wykonania tego zadania. Chcę porównać kilka linii z wieloma wyrażeń regularnych i pobrać pasującą grupę. W Ruby byłoby coś takiego:Python porównujący ciąg znaków z kilkoma wyrażeń regularnych

# 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 

Moje próby w Pythonie zwracają się dość brzydki, ponieważ grupa zwracany jest z wywołania dopasować/wyszukiwanie w wyrażeniu regularnym i Python ma zadanie w warunkowych lub przełączaj instrukcje. Jaki jest Pythonowy sposób (lub myślenie!) Na temat tego problemu?

+1

Zobacz http://stackoverflow.com/questions/2554185/match-groups-in-python. – PaulMcG

+0

Tak, to pytanie było tym, czego szukałem - dzięki! – maerics

Odpowiedz

0

Paul McGuire's solution z użyciem klasę pośrednią REMatcher która wykonuje mecz, przechowuje grupę mecz i zwraca wartość logiczną na sukces/fail okazało się produkować kod najbardziej czytelny dla tego celu.

1

Coś takiego, ale ładniejsza:

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

for regex in regexes: 
    m = regex.match(s) 
    if m: 
    print m.groups() 
    break 
else: 
    print 'No match' 
+1

Próbowałem czegoś podobnego, ale chcę podjąć różne akcje w oparciu o to, które dopasowuje wyrażenie, więc przeniosłem się z listy do słownika odwzorowującego wyrażenia regularne do lambd, które mają być wywołane, jeśli znaleziono dopasowanie, ale tworzy to trochę mylącego kodu ... – maerics

1

Istnieje kilka sposobów, aby „wiążą nazwę w locie” w Pythonie, tak jak mój stary recipe dla „przypisać i test”; w tym przypadku pewnie bym wybrać inny taki sposób (zakładając, Python 2.6, wymaga pewnych niewielkich zmian Jeśli pracujesz ze starą wersją Pythona), coś jak:

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 

Wiele drobnych szczegółów może być regulowana, oczywiście (na przykład po prostu wybrałem (.*) zamiast (.*?) jako dopasowującą grupę - są one równoważne, biorąc pod uwagę natychmiastowe podążanie za $, więc wybrałem krótszą formę ;-) - można było wstępnie skompilować RE, poprawić różne rzeczy niż krotka pats_mark (np. z dyktatem indeksowanym wzorami RE), itp.

Ale najważniejsze pomysły, jak sądzę, mają destrukcja danych i wiązanie obiektu dopasowania do nazwy w locie z podwyrażeniem for mo in [re.match(p, line)], "pętla" na liście pojedynczych elementów (genexps wiążą nazwy tylko za pomocą pętli, a nie przez przypisanie - niektórzy rozważają użycie tej części Specyfikacja genexps jest "trudna", ale uważam to za całkowicie dopuszczalny idiom Pythona, szczególnie. odkąd był rozpatrywany w czasach, gdy lista zawierała w pewnym sensie "przodków" genexps).

-1

Twoje wyrażenie regularne bierze wszystko, co jest po trzecim znaku.

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" 
+0

fajny sposób, ale użyłbym podziału i porównania: begin, rest = line.split (':', 1) jeśli zaczyna się == "A": etc ... – moshez

+0

To jest dobre, ale jestem Poszukując czegoś bardziej ogólnego, proste wyrażenie regularne służy jedynie do celów wyjaśniających, a rzeczywiste wyrażenie regularne byłoby dość złożone. – maerics