RegEx und Assertionen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
DocFisher
User
Beiträge: 50
Registriert: Donnerstag 29. November 2007, 21:04
Wohnort: Berlin
Kontaktdaten:

Hallo,

ein Statement vorweg: Ich bin blutiger Anfänger bezüglich Python und programmieren im allgemeinen. Ebenfalls beim RegExen (heute erster Kontakt...).
Wer sich durch "Newbie"-Fragen gestört fühlt, sollte diesen Thread einfach ignorieren.

Jetzt zum Thema: Um Python kennen zu lernen, habe ich mich an die Pythonchallenge gewagt. In Level 3 geht es um Reguläre Ausdrücke. Mittlerweile habe ich das Rätsel gelöst, ich dachte es wären "schärfere" Bedingungen... Bei meinem ersten Ansatz (mit zu scharfen Bedingungen...) ist mir ein Problem untergekommen, welches ich nicht ganz verstehe...

Angenommen wir haben diesen string:

Code: Alles auswählen

teststring = 'jhskjfhAAAAbBBBBjkhsCCCaCCCsDDDsD'
und ich möchte mit einen RegEx alle Kleinbuchstaben finden, die von genau(!) 3 gleichen(!) Großbuchstaben flankiert sind, war meine Herangehensweise:

Code: Alles auswählen

re.compile('[^\2](([A-Z])\2{2})[a-z](?=\1[^\2])')
Damit erreiche ich aber nur, dass mir bei obigem Beispiel-String zwar die Stelle sCCCaCCCs gefunden wird, aber ich schaffe es nicht, durch eine Lookbehind-Assertion den "sCCC" Teil "weg" zu schaffen. Den CCCs-Schwanz schneide ich mit der (?=)-Assertion heraus. Wenn ich aber Versuche, die Lookbehind-Assertion am Anfang einzubauen:

Code: Alles auswählen

re.compile('(?<=[^\2](([A-Z])\2{2}))[a-z](?=\1[^\2])')
gibt es keine Matches mehr.
Liegt das fehlverhalten evt. daran, dass ich die Assertion über einen Ausdruck vornehme, der Zugriff auf eigene Subsegmente ( \2 ) enthält?
Falls ja, wie kann ich dieses Verhalten umgehen?

Über Hinweise würde ich mich sehr freuen,
viele Grüße!
BlackJack

Der Teilausdruck '[^\2]' bedeutet "ein Zeichen das kein Backslash oder nicht die Ziffer 2 ist". Das ist kein Bezug auf die zweite Gruppe des Matches. Wobei man die Gruppen auch erst referenzieren kann, nachdem sie gematcht wurden.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Muss es denn ein einzelner regulärer Ausdruck sein? Meines Wissens kannst du nicht gleichzeitig eine Gruppe unterdrücken und auf sie referenzieren. Ich würde das Problem so lösen:

Code: Alles auswählen

ex = "CCCjkjljCCCaCCCjAAAlksaAAA"
[x.group(2) for x in re.finditer(r"([A-Z]{3})([a-z]+)(?=\1)", ex)]
Stefan
DocFisher
User
Beiträge: 50
Registriert: Donnerstag 29. November 2007, 21:04
Wohnort: Berlin
Kontaktdaten:

Hallo BlackJack,

vielen Dank für Deine Antwort!

Verstehe ich das falsch? Ich dachte, dass in obigem Beispiel die erste Gruppe des Matches die Tripel-Kombination und der 2. Match nur ein Element aus der Tripelkombination(wurde ja daraus gebildet) ist.
Wie wäre denn eine mögliche Negierung der 2. Gruppe am Anfang? Oder ist das gerade der springende Punkt, dass "RegEx" noch garnicht "weiß", dass \2 die 2. Gruppe sein soll?
Hast Du einen Tipp, wie ich so ein Problem

1. Suche 3 identische Elemente(z.B. 'C') gefolgt von einem anderen Element (z.B.'s')
mit der Bedingung
2. vor den 3 identischen Elementen ('CCC') darf das Element ('C')nicht stehen

lösen, oder womit ich google bemühen könnte?!?

EDIT: Ich habe gerade erst die Antwort von sma gesehen. Das werde ich erstmal versuchen nachzuvollziehen. Danke Stefan!
DocFisher
User
Beiträge: 50
Registriert: Donnerstag 29. November 2007, 21:04
Wohnort: Berlin
Kontaktdaten:

Hallo Stefan,

Deine Lösung in die Konsole geworfen:

Code: Alles auswählen

>>>ex = "CCCjkjljCCCaCCCjAAAlksaAAA" 
>>> [x.group(2) for x in re.finditer(r"([A-Z]{3})([a-z]+)(?=\1)", ex)]
['jkjlj', 'a', 'lksa']
findet zwar 'a', aber eben leider auch die anderen.... Aber da kann man ja das '+' weglassen, dann klappst!
Aber jetztmuss ich mir auch erstmal anschauen, wass re.finditer und x.group macht. Aller Anfang ist eben schwer.

Vielen Dank für Eure Hilfe!!!
Gruß, Jens
BlackJack

Tja, ich hätte gedacht, dass folgendes funktioniert, tut es aber leider nicht für mehr als drei gleiche Grossbuchstaben vor dem Kleinbuchstaben. Das wird trotzdem erkannt.

(([A-Z]){3})(?<!\2{4})[a-z]\1(?!\2)
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

DocFisher hat geschrieben:findet zwar 'a', aber eben leider auch die anderen....
Du schriebst "alle Kleinbuchstaben finden, die von genau(!) 3 gleichen(!) Großbuchstaben" daher dachte es, es sollen auch mehrere sein können. Wie du's ändern kannst, hast du ja schon selbst herausgefunden.

Stefan
DocFisher
User
Beiträge: 50
Registriert: Donnerstag 29. November 2007, 21:04
Wohnort: Berlin
Kontaktdaten:

Hallo BlackJack,
wenn ich es richtig sehe, taucht hier aber das Problem auf, dass der gesamte Suchausdruck weitergegeben wir, also CCCaCCC statt nur 'a'.
Aber ich merke, dass ich mich wohl ersteinmal noch ein bischen mit RegEx beschäftigen muss...

Aber nochmals vielen Dank.

Falls ich eine elegante Lösung finde, poste ich wieder.

Nur jetzt muss ich mich leider ans Lernen für mein (PC-fremdes...) Examen machen :-( 11 Days to go...

Einen schönen Tag Euch noch!!!!!
Antworten