2016-07-25 16 views
2

Sagen, ich habe zwei Arten von Strings:Python regulärer Ausdruck mit oder und re.search

str1 = 'NUM-140 A Thing: Foobar Analysis NUM-140' 
str2 = 'NUM-140 Foobar Analysis NUM-140' 

für beide, ich will 'Foobar' passen (was alles sein könnte). Ich habe folgendes versucht:

m = re.compile('((?<=Thing:).+(?= Analysis))|((?<=\d).+(?= Analysis))') 

ind1 = m.search(str1).span() 
match1 = str1[ind1[0]:ind1[1]] 

ind2 = m.search(str2).span() 
match2 = str2[ind2[0]:ind2[1]] 

jedoch match1 kommt zu 'A Thing: Foobar', die das Spiel für das zweite Muster zu sein scheint, nicht der erste. Einzeln angewendet (Muster 1 bis str1 und Muster 2 bis str2, ohne |), entsprechen beide Muster 'Foobar'. Ich habe damit gerechnet, dass dies aufhört, wenn das erste Muster übereinstimmt. Dies scheint nicht der Fall zu sein. Was vermisse ich?

+1

Das Problem ist, dass in der 7. Position (während des Zeichen raubend ' 0 ') die Regex kann das Match schon machen. – horcrux

+0

Oh, das stimmt. Die erste Übereinstimmung, die es findet, ist _is_ mit dem zweiten Muster. Irgendwie hat das verpasst. – dieggsy

+0

hast du 're.compile (". * Foobar. * ") Versucht' –

Antwort

0

Wenn Sie benannte Gruppen verwenden, z. B. (?P<name>...), können Sie leichter debuggen. Beachten Sie jedoch die Dokumentation für span.

https://docs.python.org/2/library/re.html#re.MatchObject.span

Spanne ([Gruppe]) Für Matchobject m, kehren die 2-Tupel (m.start (Gruppe), m.end (Gruppe)). Beachten Sie, dass, wenn die Gruppe nicht zur Übereinstimmung beigetragen hat, dies (-1, -1) ist. Gruppe ist standardmäßig auf Null gesetzt, die gesamte Übereinstimmung.

Sie geben nicht die Gruppennummer ein.

Warum verwenden Sie überhaupt span? Verwenden Sie einfach m.search(str1).groups() oder ähnliche

1

Gemäß der Dokumentation,

Da die Zielzeichenfolge abgetastet wird, REs getrennt durch ‚|‘ werden von links nach rechts ausprobiert. Wenn ein Muster vollständig übereinstimmt, wird dieser Zweig akzeptiert. Dies bedeutet, dass B, sobald A übereinstimmt, nicht weiter getestet wird, auch wenn es zu einer längeren Gesamtübereinstimmung führen würde. Mit anderen Worten, das '|' Betreiber ist nie gierig.

Aber das Verhalten scheint anders zu sein:

import re 

THING = r'(?<=Thing:)(?P<THING>.+)(?= Analysis)' 
NUM = r'(?<=\d)(?P<NUM>.+)(?= Analysis)' 
MIXED = THING + '|' + NUM 

str1 = 'NUM-140 A Thing: Foobar Analysis NUM-140' 
str2 = 'NUM-140 Foobar Analysis NUM-140' 

print(re.match(THING, str1)) 
# <... match='Foobar'> 
print(re.match(NUM, str1)) 
# <... match='A Thing: Foobar'> 
print(re.match(MIXED, str1)) 
# <... match='A Thing: Foobar'> 

Wir würden erwarten, dass, weil THING Spiele ‚Foobar‘, das MIXED Muster, dass ‚Foobar‘ bekommen würde, und beenden Sie die Suche. (Stand der Dokumentation)

Weil es nicht so dokumentiert arbeitet, hat die Lösung auf Pythons or Kurzschlüsse verlassen:

print(re.search(THING, str1) or re.search(NUM, str1)) 
# <_sre.SRE_Match object; span=(17, 23), match='Foobar'> 

print(re.search(THING, str2) or re.search(NUM, str2)) 
# <_sre.SRE_Match object; span=(8, 14), match='Foobar'> 
+0

Danke für Ihre Antwort. Interessanterweise scheint es, wenn man diese Dokumentation liest, dass das Verhalten _might_ tatsächlich folgt, nur der Wortlaut ist mehrdeutig.Es wird nicht spezifiziert, was "wie die Zeichenfolge gescannt wird" wirklich bedeutet, also könnte es die RE von links nach rechts _per Zeichen_ oder eine Subtilität wie diese überprüfen, was zu dem Verhalten führen würde, das wir sehen. (ähnlich wie der Kommentar von @horcrux zu meiner ursprünglichen Frage vorgeschlagen hat). Auf jeden Fall denke ich, dass "oder" der sauberste Weg ist, um das beabsichtigte Verhalten zu erreichen, also danke! – dieggsy