Stefan: Regex immer mal wieder

Beitrag lesen

Hallo, Das mit den regulären Audrücken ist immer noch ein rotes Tuch für mich. Ich nutze sie und dennoch sind es oft die simpelsten darunter die mich zum verzweifeln bringen.

Das liegt aber auch daran, dass es wirklich keine gute Dokumentation, bzw gutes Tutorial darüber gibt.

Ist das leidliche Thema wie bei allem, wers verstanden hat, ist nicht mehr in der Lages es zu erklären, weil ihm viele Erklärungen dabei als selbstverständlich vorkommen.

Und, es geht vielen wie mir, also wenn jemand von euch (den Wissenden) in der Lage wäre ein Tutorial zu schreiben, das wirklich jeder Idiot versteht, wäre bestimmt ein Besucher Magnet. Habe wirklich heute mal wieder unzählige abgegrast und doch bin ich so klug als wie zuvor.

Aber jetzt zu meinem Problem:

Der Text : "sonne.html" "sonne2.html" "sonne3.html" "katze/sonne4.html" "sonnehtml.jpg" "sonne2.csv" "sonne3.txt" "katze/sonne4.php"

Dann will ich zb alles finden zwischen "" was "atz" drin hat. Das heisst die katzen würde ich bekommen.

Sollte doch einfach sein:

$reg = !! Erst mal delimiter festlegen

$reg = !""!  Dann zwischen " suchen

$reg =!""!is  egal ob gross oder klein und über mehrer zeilen

$reg = !".*"!is  Am Anfang darf irgendwas stehen

$reg = !".*[atz]"!is  Dann muss atz auftauchen

$reg = !".[atz]."!is  Am Ende wieder irgendwas

$reg = !".?[atz].?"!is     gierig abschalten (auch so eine sache die Keiner richtig erklärt)

Sooo heraus kommt: Array (     [0] => Array         (             [0] => "sonne.html"             [1] => "sonne2.html"             [2] => "sonne3.html"             [3] => "katze/sonne4.html"             [4] => "sonnehtml.jpg"             [5] => "sonne2.csv" "sonne3.txt"             [6] => "katze/sonne4.php"         )

)


Ich weiss aber nicht warum, und viel wichtiger wo ist mein Denkfehler ? Ich weiss das ist bestimmt einfach, aber genau das machts so schwierig.

Im übrigen suche ich eigentlich genau das Gegenteil, aber wenns einfach schon nicht klappt... $reg = !".?[^atz].?"!is

Gruss Stefan

Anhang Das folgende sind Kurznotizen die ich mir letzte Nacht gemacht hatte, als ich mir diese verd...ten Regexes wieder zu Gemüte geführt hatte.

Ist nur als Lesestoff und  Denkanstösse für Jemand gedacht dem es mit Regex's genau so geht wie mir. Hat also nichts mit meiner Frage zu tun. Steht auch viel Unsinn drin und somit tut es euch nicht an wenn Ihr mit regulären Ausdrücken klarkommt.

<p>------------------------------------</p> <h3>Einige Anregungen</h3> <h5>Beispielsatz: hansi hat eine realistische kur von steinen</h5>

<xmp> Beispiele <hr noshade size="1"> regex: ([a-z].+?)\s

Array (     [0] => Array         (             [0] => hansi             [1] => hat             [2] => eine             [3] => realistische             [4] => kur             [5] => von         )     [1] => Array         (             [0] => hansi             [1] => hat             [2] => eine             [3] => realistische             [4] => kur             [5] => von         ) )

##################################

![a-z].+?\s!i

! Hier ist das leerzeichen mitvorhanden auch wenn man es jetzt nicht sieht

Array (     [0] => Array         (             [0] => hansi             [1] => hat             [2] => eine             [3] => realistische             [4] => kur             [5] => von         ) )

################################

![a-z]+!i oder  !\w+!i

Das ist die kürzeste Form, dachte mir dabei buchstaben finden und mindestens einen weiteren buchstaben. Wenn U(gierig weg) nicht benutzt wird sucht er so lange bis kein buchstabe mehr kommt.

WICHTIG: Das kann man mit php auch leicht lösen zb. explode(' ',$array), aber: wenn nicht jede Trennung ein Leerzeichen ist was dann ? zb: hansi#hat&eine'realistische`kur # von steinen Hier spielt die Regex ihre Überlegenheit  voll aus, denn der ist es egal was als trenner steht hauptsache kein Buchstabe oder zahl.

Array (     [0] => Array         (             [0] => hansi             [1] => hat             [2] => eine             [3] => realistische             [4] => kur             [5] => von             [6] => steinen         ) )

wenn der string so wäre: hansi2hat&eine'realistische`kur 4# von steinen

Array (     [0] => Array         (             [0] => hansi2hat             [1] => eine             [2] => realistische             [3] => kur             [4] => 4             [5] => von             [6] => steinen         ) )

###############################

Jetzt mal ein paar Versuche. Ich verändere den Beispielsatz in: "Ein Gemälde ist meist eine realistische Interpretation"

Ich möchte aus dem Wort "realistische" das wort "ist" finden.

Das bedeutet erst mal eingrenzen, aber wie ?

also "ist" wird gesucht, was darf/kann/muss davor stehen ?

reg = ist = nur die Buchstaben "ist" [0] => Array         (             [0] => ist             [1] => ist             [2] => ist         )


Aha, also wirklich jedes "ist" wird gefunden.

Buchstaben davor ? ok also

reg = \wist = wenn es nur einer sein soll [0] => Array  (     [0] => eist     [1] => list  )

reg = \w+ = wenn es mehrere sein dürfen [0] => Array         (             [0] => meist             [1] => realist         )


Ja hier fehlt doch einer ? klar ist wird nicht gefunden, warum auch, existiert ja kein Buchstabe davor.

Hmm, jetzt will ich dieses einzelne ist aber auch haben, jedoch sollen bei den anderen wenn Buchstaben davor sind, diese auch gefunden werden. mal probieren:

reg = .+ist Oje, ganz schlecht der Gedanke: [0] => Array         (             [0] => Ein Gemälde ist meist eine realist         )

Was habe ich mir dabei gedacht ? Vor ist muss ein beliebiges Zeichen stehen, ach klar das ist ja schon falsch, kann/darf eines stehen also: Das liebe Fragezeichen anstatt plus. reg = .?ist  = "ist" gesucht davor darf ein buchstabe oder zahl stehen

und siehe da : [0] => Array         (             [0] =>  ist             [1] => eist             [2] => list         )


Dennoch, wieso klappts ? Hatte eigentlich erwartet, dass es nicht geht weils ja ein punkt ist und kein \w denn ein Leerzeichen ist doch auch ein zeichen oder nicht bzw. Warum dann überhaupt noch \w nehmen wenn der Punkt das gleiche macht ? Egal später. Nächster Versuch, mir gefällt nämlich nicht dass nur ein Buchstabe gefunden wird davor. Also mal testen:

.*?ist  [0] => Array         (             [0] =>  ist             [1] => eist             [2] => list         )

\w*?ist [0] => Array         (             [0] => Ein Gemälde ist             [1] =>  meist             [2] =>  eine realist         )

\w*?ist

Sogar mit U(nicht gierig) alles OK [0] => Array         (             [0] => ist             [1] => meist             [2] => realist         )

Dieses ist schon mal richtig aber warum ist das so ? Ich suche "ist". Davor darf ein Zeichen stehen \w (aber kein leerzeichen daher \w also und nicht ".") Aber nicht nur ein Zeichen sondern beliebig viele also \w*. Andererseits darf aber auch keins enthalten sein, also noch ?, so kommen wir zu \w*.? und natürlich zum suchbegriff "ist" also: \w*.?ist super es klappt ;-)

Grrr, klappt zwar aber nicht mit meiner Theorie. Das Fragezeichen kann ich mir sparen gleiches Ergebniss. Was hat es denn mit diesem Fragezeichen genau auf sich ?

Das Fragezeichen ? bedeutet in einem regulären Ausdruck, dass das Zeichen vor dem Fragezeichen Bestandteil der gefundenen Zeichenfolge sein darf, dass aber auch Zeichenfolgen ohne diese Zeichen gefunden werden.

Noch nicht ganz begriffen, aber später mehr dazu.


Beispielsatz nochmal geändert:

"Ein Gemälde ist m3eist eine realistische Interpretation"

Mal den Unterschied mit und ohne U(nicht gierig)

reg = !.+ist!iU

[0] => Array         (             [0] => Ein Gemälde ist             [1] =>  m3eist             [2] =>  eine realist         )

reg = !.+ist!i [0] => Array         (             [0] => Ein Gemälde ist m3eist eine realist         )

Warum der Unterschied ? Kann nur vermuten ;-)

Ohne U:  zunächst mal das allerletzte "ist" finden, dann alle Zeichen davor egal wieviele und egal ob Leerzeichen oder nicht.

Mit U: Das erste Vorkommen von "ist" finden und alle Zeichen davor, dann übriggebliebenen string mal sehen ob noch ein "ist" vorkommt wieder alles davor ( was übrigblieb) zurück usw. bis kein ist mehr da ist.

Wenn es so ist, ärgere ich mich noch mehr über die zahllosen unverständlichen Tutorials zu Regex , denn wenn ich mal das phpmanual als Vorbild nehme, Stringfunktionen  "findet von bis" "findet ab erstes Vorkommen"  usw.

Ja kann man das denn hier nicht genau so einfach erklären ?

Mit   U  = letztes Vorkommen Ohne  U  = erstes Vorkommen

Und ein Punkt als Platzhalter "." kann auch ein Leerzeichen sein. Deshalb wenn Buchstaben/Zahlen davor sein sollen "\w" sonst ".". Wobei ich immer noch nicht "\b" verstehe. Na ja, später.

#############

</xmp>

<pre> Notiz: Der + Operator soll nicht greedy sein, das heißt, er soll nicht durchmarschieren bis zum letzten Punkt, sondern nur bis zum nächsten Punkt.

Bedeutet dass dass das Fragezeichen eine besondere Bedeutung hinter einem + bekommt ? Stop bei erster Funstelle. in dem fall eine domain web.de.blabla.blabla. .+?. = web. .+.  = web.de.blabla.blabla.

Das Zeichen \b Es wurde also lediglich da Dach ^ und das Dollar Zeichen durch eine word boundary \b ersetzt. Nun stellt sich die Frage, welches Zeichen durch die word boundary \b eigentlich dargestellt wird. Die Antwort ist: Gar keines. Eine word boundary ist immer dann gegeben, wenn das Zeichen links davon ein word element ist also zur Gruppe \w gehörig und rechts davon ein non word charakter Zeichen steht. Es muss also nicht unbedingt ein Leerzeichen das sein. Dies kann man der Tatsache entnehmen, dass die email Adresse in infos@infos24.de gefunden wird. Das Zeichen \b ist selber aber kein Zeichen und die regular expression wandert durch eine word boundary auch nicht weiter.

reg = .*\s(.+@)(.+?.\w+) $banane='Zu welcher Domain gehört eigentlich die email Adresse And3-res_Ehma.nn@web-berlin.de.Ich bin der Konfliktstoff. Noch schlimmer xy_hansi-berg.-test@dom-ain.de.uk.ca.museum wird es test3@yahoo.de bei mehreren Punkten.';

[0] => Array         (             [0] => $banane='Zu welcher Domain gehört eigentlich die email Adresse And3-res_Ehma.nn@web-berlin.de.Ich bin der Konfliktstoff. Noch schlimmer xy_hansi-berg.-test@dom-ain.de.uk.ca.museum wird es test3@yahoo.de         )     [1] => Array         (             [0] => test3@         )     [2] => Array         (             [0] => yahoo.de         )

############################## Das beste von   http://www.infos24.de/phpe/handbuch/6_php_regular_expression.htm

\b\w[\w|.|-]+@\w[\w|.|-]+.[a-zA-Z]{2,4}\b

Eigene Variationen mit gleichem Ergebniss

\b[\w.-]+@\w[\w|.|-]+.[a-zA-Z]{2,4}\b

\b[\w.-]+@[\w.-]+.\w{2,4}\b

\b[\w.-]+@[\w.-]+.\w+\b

Funktioniert sehr gut weiss aber noch nicht warum genau  [0] => Array         (             [0] => And3-res_Ehma.nn@web-berlin.de.Ich             [1] => xy_hansi-berg.-test@dom-ain.de.uk.ca             [2] => test3@yahoo.de         )

###########################

Der Wildcard-Ausdruck .+, der "alles" bis zum Zeichen > holen soll, macht nämlich nicht beim nächsten > Stopp, sondern erst beim allerletzten. Durch das Anhängen des Fragezeichens, also durch Erweiterung auf .+?, beschränkt sich das Muster auf das Auffinden des nächsten >-Zeichens.

</pre>