Zur Navigation

Ein paar Fragen zu regulären Ausdrücken

1 lava

Hallo,

ich versuche gerade Quellcode von einem Freund zu verstehen. Er hat an einer Stelle, wo er ] als Zeichen meint, nicht \] , sondern \\] geschrieben. Ich bin eigentlich der Meinung, dies sei ein Fehler, und hab es gerade mal selbst in einem Codeschnipsel ausprobiert, ob die Ausgabe wirklich einen Unterschied macht. Macht sie nicht - aber ich verstehe nicht, wieso das doppelte \\ nicht stört. Tatsächlich spuckt ein <?php echo $regex; ?> mir in beiden Fällen denselben regulären Ausdruck aus, immer mit \] und nie mit \\] - also liegt es wohl an PHP selbst und nicht an der Syntax des regulären Ausdrucks, dass die Doppelung des Backslashs keine Auswirkungen hat - aber wieso ist das so???

Nächste Frage: Wenn ein Teilsuchmuster mit einem Leerzeichen beginnen soll (\s(Blabla)), wird als gefundener Match trotzdem dieses Leerzeichen nicht mit ausgegeben - kann ich irgendwie dafür sorgen, dass es dass doch wird?

Wenn ich mit preg_match_all einen Content nach einem "Tag-Anfang Ausdruck Tag-Ende" durchsuche, dann bekomme ich mehrere Matches, wenn sowas mehrmals in dem Content vorkommt. Wenn ich aber einfach nach "~[^A]*~" suche, also nach allen Zeichenfolgen ohne A, dann bekomme ich nur die Matches bis zum ersten Auftreten von A und danach keine weiteren mehr, d.h. da wird anscheinend nicht der ganze Content durchsucht, sondern nach dem ersten Teilergebnis einfach aufgehört - warum?

Wie kann ich z.B. schreiben, dass etwas die Buchstaben s,u,p,e,n,h in beliebiger Zeichenabfolge enthalten darf, aber nicht in der Zeichenabfolge suppenhuhn ??? Also sowas wie [supenh]* unter Ausschluß dieser ganz bestimmten Reihenfolge?

Danke erstmal für rasche Antworten....

05.10.2011 06:33

2 Jörg Kruse

ich versuche gerade Quellcode von einem Freund zu verstehen. Er hat an einer Stelle, wo er ] als Zeichen meint, nicht \] , sondern \\] geschrieben. Ich bin eigentlich der Meinung, dies sei ein Fehler, und hab es gerade mal selbst in einem Codeschnipsel ausprobiert, ob die Ausgabe wirklich einen Unterschied macht. Macht sie nicht - aber ich verstehe nicht, wieso das doppelte \\ nicht stört. Tatsächlich spuckt ein <?php echo $regex; ?> mir in beiden Fällen denselben regulären Ausdruck aus, immer mit \] und nie mit \\] - also liegt es wohl an PHP selbst und nicht an der Syntax des regulären Ausdrucks, dass die Doppelung des Backslashs keine Auswirkungen hat - aber wieso ist das so???

Das sind zwei Expansionsebenen. Zuerst werden durch PHP Zeichen innerhalb eines Strings expandiert,z.B. \", \' und \\. Einen Unterschied ergibt dies z.B. zwischen "\\n" und "\n" - ersteres wird als \n ausgegeben, zweiteres als Zeilenumbruch. Bei "\]" braucht es hier eigentlich keinen weiteren Backslash, aber er schadet auch nicht. Die zweite Expansionsebene ist dann die des Regex'

Nächste Frage: Wenn ein Teilsuchmuster mit einem Leerzeichen beginnen soll (\s(Blabla)), wird als gefundener Match trotzdem dieses Leerzeichen nicht mit ausgegeben - kann ich irgendwie dafür sorgen, dass es dass doch wird?

Wenn du den Match in einem Browser ausgibst, verschluckt dieser u.U. das Leerzeichen, da er die Ausgabe als HTML interpretiert. Im Quelltext sollte aber ein Leerzeichen zu finden sein

Wenn ich mit preg_match_all einen Content nach einem "Tag-Anfang Ausdruck Tag-Ende" durchsuche, dann bekomme ich mehrere Matches, wenn sowas mehrmals in dem Content vorkommt. Wenn ich aber einfach nach "~[^A]*~" suche, also nach allen Zeichenfolgen ohne A, dann bekomme ich nur die Matches bis zum ersten Auftreten von A und danach keine weiteren mehr, d.h. da wird anscheinend nicht der ganze Content durchsucht, sondern nach dem ersten Teilergebnis einfach aufgehört - warum?

Das kann ich so nicht nachvollziehen, hast du da ein detaillierteres Beispiel dafür?

Wie kann ich z.B. schreiben, dass etwas die Buchstaben s,u,p,e,n,h in beliebiger Zeichenabfolge enthalten darf, aber nicht in der Zeichenabfolge suppenhuhn ??? Also sowas wie [supenh]* unter Ausschluß dieser ganz bestimmten Reihenfolge?

Auf Anhieb habe ich da keine Idee - vielleicht fällt mir im Laufe des Tages noch was ein (muss mich jetzt erstmal anderen Sachen zuwenden)

05.10.2011 09:27 | geändert: 05.10.2011 09:28

3 lava

Mein Suppenhuhn-Problem hab ich auf folgende Weise ausgesprochen unelegant behoben, suche aber eine bessere Lösung:

Wenn ich im String
abcdupssuppenhuhnupsabc
nach
"~([^supenh]*)([supenh]*?)(suppenhuhn)?([supenh]*)([^supenh]*)~";
suche
dann wird als 1. Match abc, als 2.Match ups, als 3.Match suppenhuhn, als 4.Match ups und als 5.Match abc gefunden


Wenn ich stattdessen den String
abcupssupenhuhnupsabc (mit supenhuhn statt suppenhuhn)
nehme, wird als 1.Match abc gefunden, match 2 und 3 bleiben frei, in Match 4 kommt der ganzen [supenh]*-Kram, und Match 5 ist abc

So muss ich also jetzt noch mit PHP aussortieren, dass ich nur Strings die outputs nutzen möchte, die im 2. und 3. Match leer bleiben => damit habe ich dann garantiert nur Ausdrücke OHNE suppenhuhn. Aber so richtig perfekt ist das nicht, ich hätte es lieber rein mit Regex ohne PHP-Abfrage hingekriegt.

-----

Was die andere Frage angeht, wofür du ein Beispiel wolltest:
Ich hätte gedacht, dass bei Suche nach "~[^A]*~" in z.B. ABCDAABACDAFG
folgendes rauskäme: Match [0][0]: BCD, Match[0][1]: B, Match[0][2]: CD, Match[0][3]: FG, also dass alle Teilstrings gefunden werden, in denen kein A vorkommt - es wird aber nur der allererste Match davon gefunden und nicht weitergesucht. Das wundert mich, denn z.B. gibt ja
"~\[test [0-9]+\]([^\]\[])+\[/test [0-9]+\]~"
auch alle möglichen auffindbaren Matches; z.B. in
"Hallo, das ist ein [test 55]feiner Test[/test 55] und ich [test 6]komme gern hierher[/test 8]";
die Matches [0][0]: [test55]feiner Test[/test 55]
und [0][1]: [test 6]komme gern hierher[/test 8]
Wo liegt hier also der generelle Unterschied, wieso das Suchmuster mal mehrmals im String gesucht und gefunden wird und das andere Mal nicht?

A propos: Seh ich es richtig, dass ich allein mit Regex NICHT abfangen kann, dass bei z.B. oben genannten Beispiel, wo ja beim Öffnen- und Schließen-Tag je eine Zahl vorkommt, diese auch gleich sein soll - also wenn vorne 55 steht, soll hinten auch 55 stehen wie beim ersten Beispiel-Teilstring, während ein Beispiel-Teilstring wie der zweite eigentlich aussortiert werden soll, weil 6 eben nicht 8 ist - das passiert momentan auch erst im PHP, da denk ich aber, es geht höchstwahrscheinlich gar nicht anders, oder????



05.10.2011 15:00

4 Jörg Kruse

Ich hätte gedacht, dass bei Suche nach "~[^A]*~" in z.B. ABCDAABACDAFG
folgendes rauskäme: Match [0][0]: BCD, Match[0][1]: B, Match[0][2]: CD, Match[0][3]: FG, also dass alle Teilstrings gefunden werden, in denen kein A vorkommt

Ich würde hier ein + statt eines * verwenden

preg_match_all("~[^A]+~", 'ABCDAABACDAFG', $matches);
echo '<pre>';
print_r($matches);
echo '</pre>';

Das ergibt bei mir folgendes:

Array
(
    [0] => Array
        (
            [0] => BCD
            [1] => B
            [2] => CD
            [3] => FG
        )

)

A propos: Seh ich es richtig, dass ich allein mit Regex NICHT abfangen kann, dass bei z.B. oben genannten Beispiel, wo ja beim Öffnen- und Schließen-Tag je eine Zahl vorkommt, diese auch gleich sein soll - also wenn vorne 55 steht, soll hinten auch 55 stehen wie beim ersten Beispiel-Teilstring, während ein Beispiel-Teilstring wie der zweite eigentlich aussortiert werden soll, weil 6 eben nicht 8 ist - das passiert momentan auch erst im PHP, da denk ich aber, es geht höchstwahrscheinlich gar nicht anders, oder????

Vielleicht als Backreference (ungetestet):

"~\[(test [0-9]+)\]([^\]\[])+\[/\\1\]~"

05.10.2011 16:43

5 lava

Hallo, das mit der Backreference hat funktioniert.
Das mit dem + statt * auch, allerdings versteh ich da nicht, warum. Weil sonst auch die leere Menge ein Nicht-A ist??? Aber wieso sucht er nicht trotzdem dann noch weiter?
---

Bzgl. der Suppenhuhnfrage habe ich das Gefühl, dass dieser Kommentar hier helfen könnte:
http://regexadvice.com/forums/thread/29004.aspx
(siehe Beispiel über cat und dog).

Allerdings bastele ich schon eine ganze Weile dran herum, zumal ich eigentlich was komplizierteres will als nur suppenhuhn aus einem string ausschließen....
eigentlich will ich aus sowas wie

[test zahl attributestring]inhalt[/test zahl]

im Attributestring die Zeichenfolge title="....." rauswerfen und alle anderen Attribute trotzdem matchen.....

Vielleicht hast du ja später dazu doch noch ein paar Tipps. LG, Lava

05.10.2011 19:05

6 Jörg Kruse

Das mit dem + statt * auch, allerdings versteh ich da nicht, warum. Weil sonst auch die leere Menge ein Nicht-A ist???

Ja

Aber wieso sucht er nicht trotzdem dann noch weiter?

Bei mir wurde auch mit dem * weiter gesucht, aber dazwischen zusätzlich leere Matches ausgegeben

eigentlich will ich aus sowas wie

[test zahl attributestring]inhalt[/test zahl]

im Attributestring die Zeichenfolge title="....." rauswerfen und alle anderen Attribute trotzdem matchen.....

Arbeitest du hierbei mit preg_replace()? da steht dir auch noch der Modifier e zur Verfügung. Vielleicht wäre das ein Ansatz, die Fundstellen mit einer Funktion zu bearbeiten, welche auch überprüft, ob diese dem genannten String nicht entsprechen.

Siehe hierzu auch:

http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

... und Beispiel 4 auf dieser Seite:

http://www.php.net/manual/en/function.preg-replace.php

05.10.2011 20:13

... 3 Jahre und 6 Monate später ...

7 Ranma (Gast)

Also ich hätte da einen Vorschlag:
#(?(^suppenhuhn)[supenh])#
Falls es überhaupt noch jemanden interessiert.
Ranma

11.04.2015 01:14

Beitrag schreiben (als Gast)

Die Antwort wird nach der Überprüfung durch einen Moderator freigeschaltet.





[BBCode-Hilfe]