2013-08-25 28 views
5

Mam plik zawierający kilka ciągów takich jak "size = XXX;". Próbuję po raz pierwszy modułu Pythona i jestem nieco zdumiony następującym zachowaniem: jeśli użyję potoku dla "lub" w wyrażeniu regularnym, widzę tylko bit tego dopasowania. Np .:re.findall nie zwraca pełnego dopasowania?

>>> myfile = open('testfile.txt','r').read() 
>>> print re.findall('size=50;',myfile) 
['size=50;', 'size=50;', 'size=50;', 'size=50;'] 
>>> print re.findall('size=51;',myfile) 
['size=51;', 'size=51;', 'size=51;'] 
>>> print re.findall('size=(50|51);',myfile) 
['51', '51', '51', '50', '50', '50', '50'] 
>>> print re.findall(r'size=(50|51);',myfile) 
['51', '51', '51', '50', '50', '50', '50'] 

Część "size =" zniknęła. (Mimo to jest z pewnością używany w wyszukiwaniu, w przeciwnym razie uzyskałoby więcej wyników). Co ja robię źle?

Odpowiedz

19

problem masz jest, że jeśli regex że re.findall próbuje dopasować rejestruje grupy (czyli części regex, które są zamknięte w nawiasach), to zwracane są grupy, a nie dopasowany ciąg.

Jednym ze sposobów rozwiązania tego problemu jest użycie grup niezapisujących (poprzedzonych prefiksem ?:).

>>> import re 
>>> s = 'size=50;size=51;' 
>>> re.findall('size=(?:50|51);', s) 
['size=50;', 'size=51;'] 

Jeśli regex że re.findall próbuje dopasować niczego nie uchwycić, zwraca całość dopasowane ciąg.

Chociaż użycie opcji character classes może być najprostszą opcją w tym konkretnym przypadku, grupy niezapisujące zapewniają bardziej ogólne rozwiązanie.

2

'size=(50|51);' oznacza szukasz size=50 lub size=51 ale tylko dopasowanie 50 lub 51 część (zwrócić uwagę na nawiasy), dlatego nie zwraca sign=.

Jeśli chcesz sign= powrócił, można zrobić:

re.findall('(size=50|size=51);',myfile) 
+2

'(...)' definiuje grupę dopasowania. Możesz również użyć '(size = (50 | 51)), w którym będziesz miał dwie grupy dopasowań, z których pierwsza będzie pełna' size = 5X', a druga będzie tylko częścią '5X'. – korylprince

1

Myślę, że chcesz użyć [] zamiast(). [] wskazujące zestaw znaków podczas() wskazujące dopasowanie grupy. Spróbuj czegoś takiego:

print re.findall('size=5[01];', myfile) 
+0

tak po prostu edytowane, thx – marcadian

+0

pomocne, ale buduję do bardziej skomplikowanego regex, gdzie będę potrzebował() –

5

Gdy wyrażenie regularne zawiera nawiasy, złapią ich zawartości do grup, zmieniając zachowanie findall() tylko powrócić do tych grup. Oto odnośny odcinek od the docs:

(...)

zestawienia cokolwiek jest wyrażenie regularne wewnątrz nawiasów, i wskazuje początek i koniec grupy; zawartość grupy można odzyskać po zakończeniu meczu i można ją później dopasować za pomocą specjalnej sekwencji \number, opisanej poniżej jako . Aby dopasować literały '(' lub ')', użyj \( lub \) lub zawrzyj je wewnątrz klasy znaków: [(] [)].

Aby uniknąć tego problemu, można użyć zakaz robienia grupę:

>>> print re.findall(r'size=(?:50|51);',myfile) 
['size=51;', 'size=51;', 'size=51;', 'size=50;', 'size=50;', 'size=50;', 'size=50;'] 

Znowu z docs:

(?:...)

Niezapisywanie wersja zwykłych nawiasów. Pasuje do dowolnego wyrażenia regularnego w nawiasach, ale podciągu dopasowanego przez grupę nie można odzyskać po wykonaniu dopasowania lub odwołaniu się do niego później.

Powiązane problemy