2012-11-27 9 views

Antwort

40

Pythons direkt diese Funktion nicht unterstützen, aber man kann es emulieren eine Breite von Null Look-Ahead-Assertion unter Verwendung von ((?=RE)), die mit der vom aktuellen Punkt übereinstimmt gleiche Semantik wollen Sie, eine benannte Gruppe ((?P<name>RE)) in der Look-Ahead setzen und dann einen Namen Rückreferenzierung ((?P=name)) mit exakt übereinstimmen, was auch immer die Null-Breite Behauptung abgestimmt. In Kombination zusammen, das gibt Ihnen die gleiche Semantik, auf Kosten eine zusätzliche Anpassungsgruppe zu schaffen, und eine Menge von Syntax.

Zum Beispiel der Link das Beispiel Rubin bereitgestellt gibt von

/"(?>.*)"/.match('"Quote"') #=> nil 

Wir, dass in Python als solche emulieren kann:

re.search(r'"(?=(?P<tmp>.*))(?P=tmp)"', '"Quote"') # => None 

Wir können zeigen, dass ich etwas Nützliches tue, und spuckt nicht nur Leitungsrauschen aus, denn wenn wir es so ändern, dass die innere Gruppe das letzte " nicht isst, passt es immer noch:

re.search(r'"(?=(?P<tmp>[A-Za-z]*))(?P=tmp)"', '"Quote"').groupdict() 
# => {'tmp': 'Quote'} 

Sie können auch anonyme Gruppen und numerische Rückreferenzierungen verwenden, aber dies wird furchtbar voller Line-Lärm:

re.search(r'"(?=(.*))\1"', '"Quote"') # => None 

(Full Disclosure: Ich lernte diesen Trick aus perlre Dokumentation Perl, die es unter der Dokumentation erwähnt für (?>...).)

Neben der richtigen Semantik hat dies auch die entsprechenden Leistungseigenschaften. Wenn wir Port ein Beispiel aus perlre:

[[email protected]:~/tmp]$ cat re.py 
import re 
import timeit 


re_1 = re.compile(r'''\(
          (
          [^()]+   # x+ 
          | 
          \([^()]* \) 
          )+ 
         \) 
        ''', re.X) 
re_2 = re.compile(r'''\(
          (
          (?=(?P<tmp>[^()]+))(?P=tmp) # Emulate (?> x+) 
          | 
          \([^()]* \) 
          )+ 
         \)''', re.X) 

print timeit.timeit("re_1.search('((()' + 'a' * 25)", 
        setup = "from __main__ import re_1", 
        number = 10) 

print timeit.timeit("re_2.search('((()' + 'a' * 25)", 
        setup = "from __main__ import re_2", 
        number = 10) 

Wir sehen eine dramatische Verbesserung:

[[email protected]:~/tmp]$ python re.py 
96.0800571442 
7.41481781006e-05 

Welche bekommt nur noch dramatischer, als wir die Länge des Suchbegriffs erstrecken.

-2

von http://docs.python.org/2/library/re.html#regular-expression-syntax

(? P < namen> ...)

ähnlich wie reguläre Klammern, aber die von der Gruppe abgestimmt Teilzeichenfolge ist innerhalb des Restes des regulären Ausdrucks über die symbolischen Gruppennamen Name. Gruppennamen müssen gültige Python Bezeichner sein, und jeder Gruppenname darf nur einmal innerhalb eines regulären Ausdrucks definiert werden. Eine symbolische Gruppe ist auch eine nummerierte Gruppe, so als ob die Gruppe nicht benannt wäre. So kann die Gruppe id im folgenden Beispiel auch als nummerierte Gruppe 1 referenziert werden.

Wenn das Muster beispielsweise (? P [a-zA-Z _] \ w *) ist, kann die Gruppe referenziert werden durch seinen Namen in Argumenten Methoden der Spiel-Objekte wie m.group (‚ID‘) oder m.end (‚id‘), und auch nach Namen in dem regulären Ausdruck selbst (unter Verwendung von (& Delta; P = id)), und Ersatztext für .sub() (mit \ g).

(? P = name)

Matches whatever text was matched by the earlier group named name. 
+2

Benannte Übereinstimmungen sind nicht dasselbe wie atomische Gruppierung. –

+0

ah. Entschuldigung, lies die docs-Seite falsch. Nein, ich glaube nicht, dass ich jemals davon in Python gehört habe. –

10

Nach this table ist die Antwort nein. Ein RFE wurde erstellt, es zu Python 3 hinzufügen, aber wurde zugunsten des neuen regex Modul zurückgegangen, die es unterstützt:

>>> import regex 
>>> regex.match('"(?>.*)"', '"Quote"') 
>>> regex.match('"(.*)"', '"Quote"') 
<_regex.Match object at 0x00C6F058> 

Hinweis: regex für Python ist auch verfügbar 2.

+1

das 'Regex' Modul, das Sie verbunden haben, ist das gleiche Regex-Modul aus dem Python-Fehler, den Sie verbunden haben, d. H. Es gibt keine Unterstützung in Python 3.3 stdlib – jfs

+0

@ J.F.Sebastian Oh, ok! Ich dachte, Python 3 benutze noch immer 're' Modul, da ich Python 2 immer nur verwendet habe, war ich mir nicht sicher und nahm an, dass es sich auf dasselbe Modul bezieht. (* Edit: * NVM das, sah gerade, was falsch war: Ich schaute auf [diese RFE] (http://bugs.python.org/issue433030), die als ein Duplikat der einen geschlossen wurde, die ich in der Antwort erwähnte Ich werde es aktualisieren) – mgibsonbr

+0

jetzt, dass Sie den Link geändert haben, macht mein vorheriger Kommentar keinen Sinn. Für die Aufzeichnung waren die Links http://pypi.python.org/pypi/regex und http://bugs.python.org/issue2636 – jfs

0

Es scheint, nicht.

http://www.regular-expressions.info/atomic.html

Atomic Gruppierung wird von den meisten modernen Varianten regulärer Ausdrücke unterstützt, einschließlich der JGsoft Geschmack, Java, PCRE, .NET, Perl und Ruby.

Sie können die nicht-Capturing-ness von ihnen emulieren, indem unter Verwendung von nicht-zwischengespeicherten Gruppen (?:RE), aber wenn ich es richtig zu lesen, das wird noch nicht gibt Ihnen die Optimierung Vorteile.