Miriam Tolke: Regex

Hallihallo,

ich habe ein kleines Verständnisproblem.
In PHP verlieren Sonderzeichen wie $ . + usw. ihre Sonderfunktion. Wie ist das aber in Perl - dazu habe ich leider nichts gefunden.
Ich verwende die folgenden Regex im preg_match-Aufruf von PHP.

"1.0" und /([0-9.]+)/      # matcht
"1x0" und /([0-9.]+)/      # matcht nicht

Das sieht also so aus, als würde der Punkt hier wirklich nur als Punkt gelten.

"1\0" und /([0-9\.]+)/      # matcht nicht

Ups?

"1\0" und /([0-9]+)/      # Fehler

Hier scheint der Backslash einfach weiter als Escape zu gelten und escapet die Klammer.

"1\0" und /([0-9\]+)/      # Fehler

Hier escapet er aber nicht sich selbst, sondern wieder die Klammer.

Also alles in allem recht inkonsistent.
Was ist jetzt also Sache und wie kann ich einen Backslash als Backslash schreiben?

Tschüß,
Miriam

  1. Hi,

    Das sieht also so aus, als würde der Punkt hier wirklich nur als Punkt gelten.

    in einer Zeichenklasse ist dem so, ja.

    "1\0" und /([0-9\.]+)/      # matcht nicht

    "" ist das Escape-Zeichen, d.h. es nimmt dem folgenden "" seine Sonderbedeutung. Hier versuchst Du also (wenn man es auflöst), "1\0" auf "/([0-9.]+)/" zu matchen, was klappen sollte. Tut es das nicht, hast Du möglicherweise anderswo im Code einen Fehler.

    "1\0" und /([0-9]+)/      # Fehler

    Die Zeichenklasse enthält hier die Zeichen 0-9, ], +, ) und /, endet jedoch nicht.

    Hier scheint der Backslash einfach weiter als Escape zu gelten und escapet die Klammer.

    Korrekt.

    "1\0" und /([0-9\]+)/      # Fehler

    Nein, kein Fehler. Ich glaube, Du hast ein grundsätzliches Syntax-Problem.

    Also alles in allem recht inkonsistent.

    Eigentlich ist es bei Perl sehr einfach, im Gegensatz zu vielen anderen Sprachen, in denen man noch zusätzlich innerhalb der Quotes escapen muss etc.

    Was ist jetzt also Sache und wie kann ich einen Backslash als Backslash schreiben?

    "\"

    Cheatah

    1. Hi Cheatah,

      danke für Deine Antwort!

      Das sieht also so aus, als würde der Punkt hier wirklich nur als Punkt gelten.

      in einer Zeichenklasse ist dem so, ja.

      Gut, also geht das in PHP und Perl absolut gleich - das freut mich.

      "1\0" und /([0-9\]+)/      # Fehler

      Nein, kein Fehler. Ich glaube, Du hast ein grundsätzliches Syntax-Problem.

      Ich habe unten mal meinen Code gepostet, ich kann da leider nix finden. Wenn Du mich auf meinen Fehler aufmerksam machen könntest, wäre das toll.

      Also alles in allem recht inkonsistent.

      Eigentlich ist es bei Perl sehr einfach, im Gegensatz zu vielen anderen Sprachen, in denen man noch zusätzlich innerhalb der Quotes escapen muss etc.

      Naja, alle Zeichen verlieren ihre Sonderwirkung, nur der Backslash nicht, das finde ich halt inkonsistent.

      Was ist jetzt also Sache und wie kann ich einen Backslash als Backslash schreiben?

      "\"

      Hmm, anscheinend nicht. Was ich jetzt durch rumprobieren rausgefunden habe ist, daß es mit "\" funktioniert, mit zweien aber nicht!

      Hier mein ganzer Code - zum Ausprobieren:
      <?php
       $teststring = "1\0";
       echo("<p>$teststring:".$teststring."</p>");

      if(preg_match("/([0-9\]+)/", $teststring, $arr))
       {
        echo($arr[1]."<br>");
       }
       else
        echo "Fehler";
      ?>

      Ciao,
      Miriam

      1. Hoi Miriam,

        Ich habe unten mal meinen Code gepostet, ich kann da leider nix finden. Wenn Du mich auf
        meinen Fehler aufmerksam machen könntest, wäre das toll.

        Das naechste mal sag doch bitte sofort, dass es sich um PHP, nicht um Perl handelt. Auch
        wenn die Funktion preg_match heisst, sind einige Sachen doch zu beachten :)

        Naja, alle Zeichen verlieren ihre Sonderwirkung, nur der Backslash nicht, das finde ich
        halt inkonsistent.

        Auch der verliert seine 'Sonderbedeutung'.

        Was ist jetzt also Sache und wie kann ich einen Backslash als Backslash schreiben?

        "\"

        Hmm, anscheinend nicht. Was ich jetzt durch rumprobieren rausgefunden habe ist, daß es
        mit "\" funktioniert, mit zweien aber nicht!

        Das liegt daran, dass PHP seine RegExe als Funktionsparameter an die RegEx-Engine gibt.
        Diese Funktions-Parameter sind normale Strings und werden dementsprechend ganz normal
        interpoliert. Deshalb wird aus '\' nur '', und aus '\' wird '\'. Das ist ueberigens
        eine Besonderheit von PHP: \\ muesste eigentlich zu \ werden.

        if(preg_match("/([0-9\]+)/", $teststring, $arr))

        preg_match("/([0-9\\]+)/",$teststring,$arr)

        oder

        preg_match('/([0-9\]+)/',$teststring,$arr);

        Gruesse,
         CK

        1. Hi Christian,

          Das naechste mal sag doch bitte sofort, dass es sich um PHP, nicht um Perl handelt. Auch
          wenn die Funktion preg_match heisst, sind einige Sachen doch zu beachten :)

          Mal abgesehen davon, daß ich eben um diese Besonderheit nicht wußte, hatte ich doch in meinem ersten Beitrag geschrieben "Ich verwende die folgenden Regex im preg_match-Aufruf von PHP."

          Hmm, anscheinend nicht. Was ich jetzt durch rumprobieren rausgefunden habe ist,
          daß es mit "\" funktioniert, mit zweien aber nicht!

          Das liegt daran, dass PHP seine RegExe als Funktionsparameter an die RegEx-Engine gibt.
          Diese Funktions-Parameter sind normale Strings und werden dementsprechend ganz normal
          interpoliert. Deshalb wird aus '\' nur '', und aus '\' wird '\'. Das ist ueberigens
          eine Besonderheit von PHP: \\ muesste eigentlich zu \ werden.

          Klick. Das isses also, verstanden.
          Danke für diese Klarstellungen!

          Ciao,
          Miriam

          1. Hoi Miriam,

            Mal abgesehen davon, daß ich eben um diese Besonderheit nicht wußte, hatte ich doch in
            meinem ersten Beitrag geschrieben "Ich verwende die folgenden Regex im preg_match-Aufruf
            von PHP."

            Oehm, ja, wo du es jetzt sagst... war etwas verwirrend.

            Gruesse,
             CK

      2. Hi Cheatah,

        danke für Deine Antwort!

        Das sieht also so aus, als würde der Punkt hier wirklich nur als Punkt gelten.

        in einer Zeichenklasse ist dem so, ja.

        Gut, also geht das in PHP und Perl absolut gleich - das freut mich.

        "1\0" und /([0-9\]+)/      # Fehler

        Nein, kein Fehler. Ich glaube, Du hast ein grundsätzliches Syntax-Problem.

        Ich habe unten mal meinen Code gepostet, ich kann da leider nix finden. Wenn Du mich auf meinen Fehler aufmerksam machen könntest, wäre das toll.

        Also alles in allem recht inkonsistent.

        Eigentlich ist es bei Perl sehr einfach, im Gegensatz zu vielen anderen Sprachen, in denen man noch zusätzlich innerhalb der Quotes escapen muss etc.

        Naja, alle Zeichen verlieren ihre Sonderwirkung, nur der Backslash nicht, das finde ich halt inkonsistent.

        Was ist jetzt also Sache und wie kann ich einen Backslash als Backslash schreiben?

        "\"

        Hmm, anscheinend nicht. Was ich jetzt durch rumprobieren rausgefunden habe ist, daß es mit "\" funktioniert, mit zweien aber nicht!

        Hier mein ganzer Code - zum Ausprobieren:
        <?php
         $teststring = "1\0";
         echo("<p>$teststring:".$teststring."</p>");

        if(preg_match("/([0-9\]+)/", $teststring, $arr))
         {
          echo($arr[1]."<br>");
         }
         else
          echo "Fehler";
        ?>

        Ciao,
        Miriam

        Hallo Miriam,

        Mag mich erinnern, dass ich dieses Problem auch schon hatte.

        Folgendes habe ich nun ausprobiert...

        "1\0"  -->  "/([0-9\]+)/"
        deine Version, funktioniert anscheinend wirklich.

        "1\0"  -->  "/([\\0-9]+)/"
        sollte ja auch gehen...
        jammert aber mit No ending delimiter '/' found in...

        "1\9"  -->  "/([\\1-9]+)/"
        vielleicht gehts ja so...
        wenigstens keine Fehlermeldung.
        Das ist doch das gleiche wie oben, nur dass ich den Zahlenbereich
        anders gesetzt habe.
        Er findet aber nicht den ganzen Ausdruck.

        "1\0"  -->  "/([\0-9]+)/"
        so sollte es ja nach PHP-Referenz funktionieren.
        er findet aber nicht den ganzen Ausdruck.

        "\"  -->  "/([\]+)/"
        sollte eigentlich einen einzelnen Backslash finden.
        aber er jammert mit missing terminating ] for character class...
        er quotet sich also selber die ] weg.

        "\"  -->  "/([\]+)/"
        deine Version. funktioniert.

        "\"  -->  "/([\\]+)/"
        meine Version. funktioniert auch.

        "1\0"  -->  "/([\\0-9]+)/"
        "1\0"  -->  "/([0-9\\]+)/"
        meine Version mit Zahlenbereich, die funktioniert nun korrekt.
        gleich ob die Backslashes vor dem Zahlenbereich stehen oder dahinter.

        FOLGERUNG...

        Zu dem Fehler No ending delimiter '/' found in...
        PHP ist mit C programmiert.
        Eine Sequenz wie "\0" in einem String bezeichnet in C das Ende des Strings. Der PHP-Interpreter sieht hier also das Ende der Reg-Expression und quittiert dies mit einer Fehlermeldung weil der Reg-Expression nicht korrekt ist.
        Wenn du

        echo "ich bin \0 da";

        schreibst

        bekommst du

        "ich bin "

        Finde ich persönlich natürlich misserabel. Sollte abgefangen werden.
        Also verwende nie die Sequenz "\0" in einem String.

        Dann zu den Backslashes.
        Ich denke der PHP-Interpreter macht aus 4 Backslashes 2 und das übergibt er erst der Reg-Expression-Maschine. Die Reg-Expression-Maschine sieht dann 2 Backslashes und macht aus diesen dann einen Backslash.

        Warum das deine Spezialversion mit den 3 Backslashes am Schluss der Zeichenklasse funktioniert... keine Ahnung.

        Mir wackelt jetzt dann der Kopf vor lauter \\\\....

        Gruss, LenaLuna