Regex aufs neue
Jens S.
- php
Hallo,
immer das gleiche mit den Regex. alle paar Monate beschäftige ich
mich mal damit mit endlosen schlaflosen nächten und wenn es
dann halbwegs Erfolge bringt ist alles nach ein paar Monaten
Pause wieder vergessen, grausam.
Das Problem ist immer wieder den Anfang zu finden.
Ich möchte lediglich verschiedene Texte separieren die
verschiedene Trennzeichen haben:
-------------------------------------
##1 id1
##2Erster Eintrag
##3
Das ist mein erster Eintrag und nur ein Test.
##1 id2
##22. Eintrag
##3
Das ist mein 2. Eintrag und nur ein Test.
##1 id3
##23. Eintrag
##3
Das ist mein 3. Eintrag und nur ein Test.
##1 id4
##24. Eintrag
##3
Das ist mein 4. Eintrag und nur ein Test.
##1 id5
##25. Eintrag
##3
Das ist mein 5. Eintrag und nur ein Test.
-------------------------------
Wenn ich nun zum Beispiel die Inhalte nach ##3 bis ## folgt haben möchte, schmeisst der mir alles raus.
Jetzt las ich in meinen eigenen (nicht mehr verständlichen)
Erinnerungen, dass ich $ als Grenze einsetzen muss, aber klappt auch nicht.
preg_match_all('/##3.*##$/mus',$data,$ar3);
Wer kann helfen?
Jens
Bist du dir sicher, dass du diese Informationen nicht lieber in einem serialisierten Array speichern willst?
Ansonsten sei gesagt, dass du mittels "s" Zeilenumbrüche bei den beliebigen Zeichen mit einschliesst. Damit sucht dein regulärer Ausdruck nach allen Konstrukten, die:
mit "##3" beginnen und anschließend möglichst viele Zeichen folgen, bis am Ende des Strings ("$") der Treffer mit "##" endet. Diese Konstruktion kommt aber nicht vor, daher sollte dir ein leeres Array ausgegeben werden.
Aber bitte: In einem serialisierten Array im Sinne von:
$ar = array(
0 => array('id' => 'id1', 'eintrag' => '3. eintrag', 'text' => 'Das ist mein erster Eintrag und nur ein Test.'
.
.
.
);
speichern...
Grüße.
Danke Rafael,
Bist du dir sicher, dass du diese Informationen nicht lieber in einem serialisierten Array speichern willst?
Ja, es geht mir hier nur um ein paar Tests in Sachen Regex.
Ansonsten sei gesagt, dass du mittels "s" Zeilenumbrüche bei den beliebigen Zeichen mit einschliesst. Damit sucht dein regulärer Ausdruck nach allen Konstrukten, die:
mit "##3" beginnen und anschließend möglichst viele Zeichen folgen, bis am Ende des Strings ("$") der Treffer mit "##" endet. Diese Konstruktion kommt aber nicht vor, daher sollte dir ein leeres Array ausgegeben werden.
Ach so und ich dachte der nimmt das jeweils als Grenze und sucht dann weiter.
Aber weiter hilft mir das leider auch nicht.
Denn genau das ist mein Problem, dem regex zu sagen "bitte suche
alles was mit ##3 anfängt bis wieder mal ein ## folgt. Und dann erst wieder wenn ein neues ##3 auftaucht.
Ich kriegs nicht hin
Jens
Hello,
Ich kriegs nicht hin
Aber ich:
<?php ### find_hits.php ###
$data = "
##1 id1
##2Erster Eintrag
##3
Das ist mein erster Eintrag und nur ein Test.
##1 id2
##22. Eintrag
##3
Das ist mein 2. Eintrag und nur ein Test.
##1 id3
##23. Eintrag
##3
Das ist mein 3. Eintrag und nur ein Test.
##1 id4
##24. Eintrag
##3
Das ist mein 4. Eintrag und nur ein Test.
##1 id5
##25. Eintrag
##3
Das ist mein 5. Eintrag und nur ein Test.
";
$_treffer = array();
preg_match_all('/(##3)([^#]*\s*)(##)/m', $data, $_treffer);
echo "<pre>\n";
echo htmlspecialchars(print_r($_treffer));
echo "</pre>\n";
?>
/ Pattern Start
(##3) Friss ##3 aber packs nicht zum gesuchten Text, sondern extra
([^#]*\s*) alle Zeichen, nur das Stop-Zeichen der gesuchten Kette nicht
auch Whitespaces
(##) Ende des gesuchten Textes, nicht zum Text dazu packen
/ Pattern Ende
m auch über Zeilenumbrüche hinweg
Wie Du siehst, fehlt der 5. Eintrag, weil er nicht mit den geforderten zwei Doppelkreuzen endet. Wenn Du den auch noch haben willst, müsste man das noch mit dem $-Zeichen optional einbauen
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Ja, so klappt es.
Dank dir Tom.
Jens
Hello,
Wie Du siehst, fehlt der 5. Eintrag, weil er nicht mit den geforderten zwei Doppelkreuzen endet. Wenn Du den auch noch haben willst, müsste man das noch mit dem $-Zeichen optional einbauen
$pattern_with_last = '/(##3)([^#]*\s*)((##)|$)/m';
Nur der Vollständigkeit halber noch das Pattern, wenn man auch den letzten Eintrag haben will.
Ob da nun ganz richtig ist und _sicher_ funktioniert, weiß ich (noch) nicht, aber es funktioniert hier so, wie gewünscht.
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hello,
$pattern_with_last = '/(##3)([^#]*\s*)((##)|$)/m';
Ob da nun ganz richtig ist und _sicher_ funktioniert, weiß ich (noch) nicht, aber es funktioniert hier so, wie gewünscht.
es ist nicht sicher, wenn man zwei der Einträge hintereinander hat.
Ich habe mal 4a eingefügt. Der wird unterschlagen, weil der Eintrag 4
vorher schon die beiden ## von ##3 gefressen hat.
Daran müsste man dann also noch feilen.
$data = "
##1 id1
##2Erster Eintrag
##3
Das ist mein erster Eintrag und nur ein Test.
##1 id2
##22. Eintrag
##3
Das ist mein 2. Eintrag und nur ein Test.
##1 id3
##23. Eintrag
##3
Das ist mein 3. Eintrag und nur ein Test.
##1 id4
##24. Eintrag
##3
Das ist mein 4. Eintrag und nur ein Test.
##3
Das ist mein 4a. Eintrag und nur ein Test.
##1 id5
##25. Eintrag
##3
Das ist mein 5. Eintrag und nur ein Test.
";
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hello,
ich habe noch eine Version gebastelt.
Die ist noch realistischer im Vorgabetext
Das Pattern passt jetzt auch für den Fall 4a
<?php ### find_hits.php ###
$data = "
##1 id1
##2Erster Eintrag
##3
Das ist mein erster Eintrag und nur ein Test.
##1 id2
##22. Eintrag
##3
Das ist mein 2. Eintrag und nur ein Test.
##1 id3
##23. Eintrag
##3
Das ist mein 3. Eintrag und nur ein Test.
##1 id4
##24. Eintrag
##3
Das ist mein 4. Test und noch kein
Ende in Sicht
##3
Das ist mein 4a. Eintrag und nur ein Test.
##1 id5
##25. Eintrag
##3
Das ist mein 5. Eintrag und der letzte
Test von allen
";
$_treffer = array();
preg_match_all('/(##3)([^(##)]*\s*)(\b|$)/m', $data, $_treffer);
echo "<pre>\n";
echo htmlspecialchars(print_r($_treffer));
echo "</pre>\n";
?>
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
gudn tach!
preg_match_all('/(##3)([^(##)]*\s*)(\b|$)/m', $data, $_treffer);
hmm, die regexp ist in etwa dasselbe wie
/(##3)([^()#]*)(\b|$)/m
ich habe mir jetzt nicht die muehe gemacht, den kompletten thread zu lesen, aber habe es so verstanden, als solle alles zwischen "##3" und dem naechsten "##" (was am zeilenanfang stehen muss) gematcht werden. das ginge z.b. so
/(?:##3\n)((?:.(?!\n##))+.)/s
bei unix-zeilenumbruch. hab's nicht ausprobiert, aber die idee sollte klar sein. hilfe zu den fragezeichendingern gibt's im php oder auch im perl-manual.
prost
seth
Hello Seth,
hmm, die regexp ist in etwa dasselbe wie
/(##3)([^()#]*)(\b|$)/m
Ja, funktioniert genauso.
Allerdings ersehe ich daraus, dass ich mit dem Teil [^()#]* bzw., so wie ich ihn hatte [^(##)]* noch 'was verkehrt verstanden hatte. Ich nahm an, dass die Klammern in der Zeichenklassen-Definition auch Sonderbedeutung hätten und wollte eigentlich erreichen, dass der Stopp wirklich bei ## und nicht bei # stattfindet.
Wie macht man das dann, wenn man signieren will "nicht diese Zeichengruppe" oder geht das gar nicht?
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
gudn tach!
Wie macht man das dann, wenn man signieren will "nicht diese Zeichengruppe" oder geht das gar nicht?
das geht z.b. mit zero-width negative look-ahead bzw. look-behind assertions, siehe dazu php- oder perl-manual. das von mir angegebene beispiel mit den vielen fragezeichen nutzte sowas.
foo(?!bar)
matcht jedes "foo", dem kein "bar" folgt.
prost
seth
Hello Seth,
Wie macht man das dann, wenn man signieren will "nicht diese Zeichengruppe" oder geht das gar nicht?
das geht z.b. mit zero-width negative look-ahead bzw. look-behind assertions, siehe dazu php- oder perl-manual. das von mir angegebene beispiel mit den vielen fragezeichen nutzte sowas.
foo(?!bar)
matcht jedes "foo", dem kein "bar" folgt.
Danke für den Tipp.
Nun habe ich es hier nochmal (auf Deutsch) erklärt gefunden
http://regexp-evaluator.de/tutorial/assertions/
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hello,
Hallo,
immer das gleiche mit den Regex. alle paar Monate beschäftige ich
mich mal damit mit endlosen schlaflosen nächten und wenn es
dann halbwegs Erfolge bringt ist alles nach ein paar Monaten
Pause wieder vergessen, grausam.Das Problem ist immer wieder den Anfang zu finden.
Ich möchte lediglich verschiedene Texte separieren die
verschiedene Trennzeichen haben:
##1 id1
##2Erster Eintrag
##3
Das ist mein erster Eintrag und nur ein Test.##1 id2
##22. Eintrag
##3
Das ist mein 2. Eintrag und nur ein Test.##1 id3
##23. Eintrag
##3
Das ist mein 3. Eintrag und nur ein Test.
##1 id4
##24. Eintrag
##3
Das ist mein 4. Eintrag und nur ein Test.##1 id5
##25. Eintrag
##3
Das ist mein 5. Eintrag und nur ein Test.
Wenn ich nun zum Beispiel die Inhalte nach ##3 bis ## folgt haben möchte, schmeisst der mir alles raus.
Jetzt las ich in meinen eigenen (nicht mehr verständlichen)
Erinnerungen, dass ich $ als Grenze einsetzen muss, aber klappt auch nicht.
preg_match_all('/##3.*##$/mus',$data,$ar3);
^
|
+--- welche Zeichen lässt Du ihn denn hier fressen?
Außerdem waren doch das genau die Zeichen, die Du haben wolltest, oder?
probier mal
preg_match_all('/##3([^##]*)##$/',$data,$ar3);
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hello,
preg_match_all('/##3([^##]*)##$/',$data,$ar3);
preg_match_all('/##3([^#]*)##$/',$data,$ar3);
So muss es auch genügen ;-)
Harzliche Grüße vom Berg
http://bergpost.annerschbarrich.de
Tom
Hallo Tom,
preg_match_all('/##3([^##]*)##$/',$data,$ar3);
preg_match_all('/##3([^#]*)##$/',$data,$ar3);
So muss es auch genügen ;-)
Leider nein, auch dein erstes beispiel nicht, leeres Array.
Trotzdem danke
Jens