regex problem auch eleganter?
Christoph Rackwitz
- php
hi,
zu anfang möchte ich gestehen, bereits im selfphp forum gefragt zu haben (http://www.selfphp.info/forum/showthread.php?s=&threadid=8886) und eine lösung für das eigentliche problem ist gefunden.
meine frage ist: geht das nicht genereller und wenn ja, wie?
nun zum Problem: (preg_match)
/\s+([A-Z]{3})\s+/
matcht "... EAC ...", "... RFC ..." und "... AEI ..." (soweit OK)
es matcht aber auch "... III ...". genau diese variante möchte ich ausschließen.
gefundene lösung: alle 3 möglichkeiten durchgehen und jeweils das i ausschließen
/\s(([A-Z]{2}[A-HJ-Z])|([A-Z][A-HJ-Z][A-Z])|([A-HJ-Z][A-Z]{2}))\s/
lässt sich das auch eleganter machen? ich stelle mir etwas in der richtung vor, das äußerste pattern (\1) irgendwie mit einer bedingung zu belegen...
geht das? wenn ja, wie?
gruß
Moin Christoph
meine frage ist: geht das nicht genereller und wenn ja, wie?
So wie Du das Problem schilderst ist es doch sehr speziell.
Das würde ich auf zwei Bedingungen verteilen, dann kann man das leichter nachvollziehen.
Z.B. so
$match = (preg_match('/\s+([A-Z]{3})\s+/', $s) &&
!preg_match('/\s+(I{3})\s+/', $s));
Bzw. wenn es tatsächlich nur um " III " geht kann man das vermutlich auch einfacher haben. Z.B. mit strstr().
gefundene lösung: alle 3 möglichkeiten durchgehen und jeweils das i ausschließen
/\s(([A-Z]{2}[A-HJ-Z])|([A-Z][A-HJ-Z][A-Z])|([A-HJ-Z][A-Z]{2}))\s/
ist doch ganz gut so.
Ggf. die Reihenfolge so abändern dass der häufigste Fall zuerst steht.
So ungefähr
/\s(([A-HJ-Z][A-Z]{2})|(I[A-HJ-Z][A-Z])|(II[A-HJ-Z]))\s/
lässt sich das auch eleganter machen? ich stelle mir etwas in der richtung vor, das äußerste pattern (\1) irgendwie mit einer bedingung zu belegen...
geht das? wenn ja, wie?
Nein, so wie ich Deine Aufgabestellung verstehe geht es nicht.
Wozu soll das ganze denn gut sein, erscheint mir in der jetzigen Form
sehr konstruiert.
Vielleicht gibt es auch eine Lösung ganz ohne RegExp z.B. mit
count_chars().
Viele Grüße
lulu
Wozu soll das ganze denn gut sein, erscheint mir in der jetzigen Form
sehr konstruiert.
Vielleicht gibt es auch eine Lösung ganz ohne RegExp z.B. mit
count_chars().
Wenn man viel mit Dateien unterschiedlichsten Ursprunges (damit verbunden: unterschiedlichste Dateinamen) zu tun hat, dann ist es recht nützlich, die Dateinamen in ein einheitliches Format zu bringen.
Beispiel:
Old.Enough.To.Know.Better.-.15.Years.Of.Merge.Records.(3CD).-.EAC.LAME(APX).by_FalloutBoy.zip
Dieser Dateiname ist das reinste Chaos. Mit ein paar Regex und ein wenig Algorithmierung kann dabei dies herauskommen:
Old_Enough_To_Know_Better_-_15_Years_Of_Merge_Records_[3_CDs,EAC,LAME,APX,by_FalloutBoy].zip
Dieses Format lässt sich einfach durch Scripte auswerten und somit die Arbeit sehr vereinfachen.
In diesem konkreten Fall hätte das [A-Z]{3} Muster bei "APX" und "EAC" gegriffen. Würde der Dateiname außerhalb der [] noch ein III (römische 3) enthalten, dann hätte womöglich der Algorithmus diese III auch in die [] gepackt und damit den Sinn des Dateinamens zerstört.
Zum Thema: Der Geistige Hohlraum hat die Lösung gefunden, die mir vorschwebte.
Gruß
matcht "... EAC ...", "... RFC ..." und "... AEI ..." (soweit OK)
es matcht aber auch "... III ...". genau diese variante möchte ich ausschließen.gefundene lösung: alle 3 möglichkeiten durchgehen und jeweils das i ausschließen
/\s(([A-Z]{2}[A-HJ-Z])|([A-Z][A-HJ-Z][A-Z])|([A-HJ-Z][A-Z]{2}))\s/lässt sich das auch eleganter machen? ich stelle mir etwas in der richtung vor, das äußerste pattern (\1) irgendwie mit einer bedingung zu belegen...
Schau doch mal in der PHP-Anleitung im in schönem Deutsch Reguläre Ausdrücke Funktionen benannten Kapitel auf der Seite mit der PCRE-Syntax nach (http://www.php.net/manual/de/reference.pcre.pattern.syntax.php). Fast am Ende findest Du den Absatz Conditional subpatterns, bedingte Muster. Mit diesen kannst Du etwas bauen, was als "falls nicht III, dann nehme drei Buchstaben" funktioniert.
Am Ende Deiner Studien sollte /\s(?(?!III)([A-Z]{3}))\s/ rauskommen. ?(...) zu Beginn enthält die zu prüfende Bedingung, ?!III darin ist ein Vorausgucker, der prüft, ob an dieser Stelle kein III folgt (das Gegenteil wäre ?=III, "folgt III?", die Beschreibung dazu steckt im Abschnitt Assertions). Daran schließt sich das Muster an, das bei erfüllter Bedingung für diese Textstelle benutzt wird, in diesem Fall das Dir bekannte [A-Z]{3}, in runden Klammern, um es einzeln auszufiltern.
Mit einem senkrechten Strich könnte man auch noch ein Muster anhängen, welches ausgeführt wird, falls die Bedingung nicht zutrifft, aber das ist hier nicht nötig.
Danke. Sowas hatte ich im Sinn, hab nur etwas gebraucht, Conditional Subpatterns und Assertions zu verstehen.
-> Problem gelöst