2016-05-05 10 views
0

Ich habe eine funktionierende regex, dass eine der folgenden Zeilen übereinstimmt:Der Versuch, die Regex zu wiederholen bricht die regex

  • Ein Interpunktion aus der folgenden Liste [.,!?;]
  • Ein Wort, das von dem Anfang des vorausgeht Zeichenfolge oder ein Leerzeichen.

Hier ist die regex in Frage ([.,!?;] *|(?<= |\A)[\-'’:\w]+)

Was ich brauche es aber zu tun ist, denn es drei Instanzen von dieser entsprechen. So wäre zum Beispiel das ideale Endergebnis in etwa so.

Sample text: "This is a test. Test" 

Output 
"This" "is" "a" 
"is" "a" "test" 
"a" "test" "." 
"test" "." "Test" 

Ich habe einfach versucht {3} bis zum Ende in der Hoffnung, das Hinzufügen von ihm 3 mal entsprechen. Dies führt jedoch dazu, dass es zu nichts oder nur gelegentlich zu einem ungeraden Zeichen passt. Die andere Möglichkeit, die ich ausprobiert habe, besteht darin, den ganzen Regex 3 Mal zu wiederholen, so wie es ([.,!?;] *|(?<= |\A)[\-'’:\w]+)([.,!?;] *|(?<= |\A)[\-'’:\w]+)([.,!?;] *|(?<= |\A)[\-'’:\w]+) ist, was schrecklich anzusehen ist, aber ich hoffte, dass es funktionieren würde. Dies hatte den merkwürdigen Effekt zu arbeiten, aber nur wenn mindestens eines der Matches eins der zuvor aufgeführten Interpunktionen war.

Alle Einsichten würden geschätzt werden.

Ich benutze die new regex module found here, so dass ich überlappende Suchen haben kann.

+1

Es wäre viel einfacher, zu sehen, wo die Dinge gehen falsch, wenn Sie tatsächlich ein kurzes und in sich geschlossenes Beispiel mit * aktuellem * Python-Code erstellen. – Evert

+0

Welchen Regex-Versuch wollten Sie als Beispiel? Der Python-Code, der es umgibt, sollte keinen Unterschied machen, aber ich kann es einfügen, wenn Sie nur Kontext wollen. – ninjanomnomSK

Antwort

1

Was mit Ihrem Ansatz falsch ist

Das ([.,!?;] *|(?<= |\A)[\-'’:\w]+) Muster entspricht eine einzelne „Einheit“ (entweder ein Wort oder einen einzigen Satz aus dem angegebenen Set [.,!?;] mit 0+ Leerzeichen gefolgt. Wenn Sie also diese gespeist Muster zum regex.findall, kehren nur könnte es nur die Chunk-Liste ['This', 'is', 'a', 'test', '. ', 'Test'].

Lösung

Sie ein etwas anderes verwenden können Ansatz: Finde alle Wörter und alle Teile, die keine Wörter sind. Hier ist eine Demo (beachten Sie, dass C'est und AUX-USB werden als einzelne „Wörter“ behandelt):

>>> pat = r"((?:[^\w\s'-]+(?=\s|\b)|\b(?<!')\w+(?:['-]\w+)*))\s*((?1))\s*((?1))" 
>>> results = regex.findall(pat, text, overlapped = True) 
>>> results 
[("C'est", 'un', 'test'), ('un', 'test', '....'), ('test', '....', 'aux-usb')] 

Hier wird das Muster hat 3 Einfanggruppen, und die zweite und die dritte enthält die gleichen Muster wie in der Gruppe 1 ((?1) ist ein Unterprogrammaufruf, der verwendet wird, um zu vermeiden, dass das gleiche Muster wie in Gruppe 1 wiederholt wird). Gruppe 2 und Gruppe 3 können durch Leerzeichen getrennt werden (nicht notwendigerweise, oder die auf ein Wort geklebte Interpunktion würde nicht übereinstimmen). Beachten Sie auch das negative Lookbehind (?<!'), das sicherstellen wird, dass C'est wie eine einzelne Entität behandelt wird.

Erklärung

Die Musterdetails:

  • ((?:[^\w\s'-]+(?=\s|\b)|\b(?<!')\w+(?:['-]\w+)*)) - Gruppe 1 Treffer:
    • (?:[^\w\s'-]+(?=\s|\b) - 1+ andere Zeichen als [a-zA-Z0-9_], Leerzeichen, ' und - sofort mit einem gefolgt Leerzeichen oder eine Wortgrenze
    • | - oder
    • \b(?<!')\w+(?:['-]\w+)*) - 1+ Wortzeichen nicht mit einem ' (aufgrund (?<!')) vorgeschaltet und mit einer Wortgrenze voran (\b) und anschließend mit 0+ Sequenzen von - oder ' mit 1+ Wort-Zeichen.
  • \s* - 0+ Whitespaces
  • ((?1)) - Gruppe 2 (gleiche Muster wie für die Gruppe 1)
  • \s*((?1)) - siehe oben
+0

Das ist interessant, ich muss das ein bisschen durcheinander bringen. Es funktioniert fast so, wie es ist, aber trennt Bindestriche und zusammengezogene Wörter wie "wir sind" oder "Röntgen". – ninjanomnomSK

+0

Bitte überprüfen Sie das Update. –

+0

Das tut, was ich brauchte, also danke! Ich würde gerne wissen, warum '([.,!?;] * | (? <= | \ A) [\ - '": \ w] +) {3} 'nicht funktioniert. – ninjanomnomSK