Jens S.: Regex aufs neue

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

  1. 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.

    1. 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

      1. 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

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
        Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

        1. Ja, so klappt es.

          Dank dir Tom.

          Jens

        2. 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

          --
          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
          Nur selber lernen macht schlau
          Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

          1. 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

            --
            Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
            Nur selber lernen macht schlau
            Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

            1. 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

              --
              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
              Nur selber lernen macht schlau
              Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

              1. 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

                1. 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

                  --
                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                  Nur selber lernen macht schlau
                  Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

                  1. 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

                    1. 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

                      --
                      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                      Nur selber lernen macht schlau
                      Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

  2. 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

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

    1. 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

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau
      Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

      1. 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