gettext regex

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • gettext regex

    Hallo mal ne frage: ich versuche das regex pattern nachzubauen mit dem auch gettext operiert, also auf strings mit _("")

    derzeit hab ich

    PHP-Code:
    /\_\((?:\'|\")([^\\1\)]+)(?:\\1\))/ 
    das ist natürlich noch nicht ganz richtig ... mein problem ist wenn _("") mehrmals vorkommt. bsp:

    PHP-Code:
    $test "das _('ist') ein _('test')"
    problem was ich hab ist das ende von ') zu finden ohne das beide platzhalter als einer gematch werden. mit [^] kann man ja nur leider zeichenklassen negieren - wie ist das wenn man einfach, anstatt einer zeichenklasse, eine zeichenkette zum negieren benutzen möchte? also bis ') das erste mal wieder vorkommt. hab mich ich das schon immer gefragt wie das geht? danke für hilfe


    f*

  • #2
    Dieses Muster scheint nach meinen ersten Tests auf deine Anforderungen zu passen:
    PHP-Code:
    $text "das _('ist') ein _('test')";

    preg_match_all('!_\\((\\'|")([^\\1)]+)\\1\\)!', $text$matches);

    echo '<pre>';
    print_r(
    $matches);
    echo '</pre>';

    //Array
    //(
    //    [0] => Array
    //        (
    //            [0] => _('ist')
    //            [1] => _('test')
    //        )
    //    [1] =&gt; Array
    //        (
    //            [0] => '
    //            [1] => '
    //        )
    //    [2] =&gt; Array
    //        (
    //            [0] => ist
    //            [1] => test
    //        )

    Sind Erklärungen zu dem Muster nötig, oder kannst du alles nachvollziehen?

    EDIT:
    In solchen Fällen arbeite ich übrigens immer ganz gerne mit Named Capturing Groups, ums etwas übersichtlicher zu machen:
    PHP-Code:
    preg_match_all('!_\\((\\'|")(?P<gettext_value>[^\\1)]+)\\1\\)!', $text$matches);

    // zu erreichen über

    $matches['gettext_value']; 
    Grüße
    Zuletzt geändert von Griecherus; 27.05.2008, 14:51.
    Nieder mit der Camel Case-Konvention

    Kommentar


    • #3
      Hallo, wow danke für die schnelle antwort!

      so im prinzip hat mein pattern auch funktioniert problem sind aber strings wie:

      PHP-Code:
      $test "das _('is)t') ein _('te)st')"
      mit dem ) im platzhalter ... das einfache ) muss durchgehen. hier schlagen beide patterns fehl. das ist genau das problem - es soll auf ') regieren aber ' und ) einzeln durchlassen.

      Kommentar


      • #4
        $pattern = '/_\((\'|")(.+)\1\)/sU';

        das negieren kann man sich m.m. sparen.

        Kommentar


        • #5
          Das dürfte schon etwas komplizierter werden... Da kommt mir spontan nur eins in den Kopf: Die Regex muss erkennen, ob eine Klammer direkt auf ein Single- oder Doublequote folgt. Ist das nicht der Fall, handelt es sich nicht um die schließende Klammer des gettext-Aufrufs. Ich versuche das mal zu basteln, kann aber dauern, ich koche und bekomme noch Besuch...

          Grüße
          Nieder mit der Camel Case-Konvention

          Kommentar


          • #6
            Original geschrieben von Griecherus
            Ich versuche das mal zu basteln, kann aber dauern, ich koche und bekomme noch Besuch...
            lass dir zeit, die lösung steht schon oben

            Kommentar


            • #7
              @3DMax: Du solltest dir das Negieren nicht sparen. Zum einen greift dein Muster nicht, zum anderen arbeitest du statt der Negierung mit einem Greedy Dot. Das kann in dem Fall, dass keine Übereinstimmung gefunden wird, eine Menge mehr Performance kosten. Greedy Dots sind generell zu vermeiden, wo es geht. In diesem Fall lässt sich die Capturing Group prima durch die negierte Klasse definieren und ist damit die günstigere Lösung. Wie genau der Greedy Dot Regex-Engine intern funktioniert und wieso das im Ernstfall ungünstig ist, erkläre ich bei Bedarf gerne bei der nächst besten Gelegenheit.
              Zuletzt geändert von Griecherus; 26.05.2008, 23:29.
              Nieder mit der Camel Case-Konvention

              Kommentar


              • #8
                Original geschrieben von Griecherus
                Zum einen greift dein Muster nicht, zum anderen arbeitest du statt der Negierung mit einem Greedy Dot. Das kann in dem Fall, dass keine Übereinstimmung gefunden wird, eine Menge mehr Performance kosten. Greedy Dots sind generell zu vermeiden, wo es geht.
                also das muster greift schon.
                und das mit der performance nehme ich dir auch nicht ab - das möchte ich sehen.

                Kommentar


                • #9
                  Original geschrieben von 3DMax
                  also das muster greift schon.
                  und das mit der performance nehme ich dir auch nicht ab - das möchte ich sehen.
                  Tut es bei mir nicht, sobald sich eine Klammer innerhalb des gettext-Strings befindest, und darum geht es dem TO. Zu deinem Zweifel: Für heute muss ich passen, aber morgen schreibe ich mal etwas dazu.

                  Grüße
                  Nieder mit der Camel Case-Konvention

                  Kommentar


                  • #10
                    Original geschrieben von Griecherus
                    Tut es bei mir nicht, sobald sich eine Klammer innerhalb des gettext-Strings befindest, und darum geht es dem TO.
                    ohne code-tags:
                    EDIT:
                    selbst ohne code tags, werden hier die backslashes verschluckt - auf zitieren gehen, dann passt es


                    $test = "das _('i's)t') ein _('test')";

                    $pattern = '/_\((\'|")(.+)\1\)/sU';

                    preg_match_all($pattern, $test, $matches);

                    echo '<pre>'.print_r($matches, true).'</pre>';

                    AUSGABE:
                    Code:
                    Array
                    (
                        [0] => Array
                            (
                                [0] => _('i's)t')
                                [1] => _('test')
                            )
                    
                        [1] => Array
                            (
                                [0] => '
                                [1] => '
                            )
                    
                        [2] => Array
                            (
                                [0] => i's)t
                                [1] => test
                            )
                    
                    )
                    funktioniert mit klammern!
                    Zuletzt geändert von 3DMax; 26.05.2008, 23:57.

                    Kommentar


                    • #11
                      So, für heute mal auf die Schnelle rausgesucht:
                      Repetition with Star and Plus. Das Stichwort im Zusammenhang mit dem Dot ist Backtracking. Und das ist, was die Regex unter Umständen sehr langsam werden lassen kann. Lies dir einfach mal durch, was eine Regex-Engine intern da macht.

                      EDIT:

                      Zu deinem Pattern: Jetzt klappts tatsächlich, entschuldige. Allerdings bleibe ich bei meinem Standpunkt hinsichtlich Negierter Charakterklassen versus Greedy Dots.



                      Grüße
                      Zuletzt geändert von Griecherus; 26.05.2008, 23:41.
                      Nieder mit der Camel Case-Konvention

                      Kommentar


                      • #12
                        Original geschrieben von Griecherus
                        Das Stichwort im Zusammenhang mit dem Dot ist Backtracking. Und das ist, was die Regex unter Umständen sehr langsam werden lassen kann. Lies dir einfach mal durch, was eine Regex-Engine intern da macht.
                        papier und html-seiten sind geduldig
                        glaub ich erst, wenn ich einen benchmark gesehen habe, der signifikante unterschiede ermittelt (schreibe ich jetzt aber nicht). ansonsten sind das alles nur theoretische annahmen.

                        bis denne - lass es dir schmecken.

                        ps: um die zeit noch kochen?

                        Kommentar


                        • #13
                          @Griecherus
                          Ich habe momentan ebenfalls keine Zeit den ganzen Regex- Code durchzusehen, aber du scheinst dich da ja sehr genau auszukennen. Kannst du statt Worten auch noch ein bisschen Code bringen?

                          Wenn du das nicht kannst versuch einmal mit ner Schleife die Performance zu testen - man erhält ein erstaunliches Resutat...

                          Kommentar


                          • #14
                            Vielleicht kann ich mich ja morgen mal dazu überreden, einen Benchmark zu schreiben... Ich verspreche aber nichts.

                            Ich spreche im Übrigen nicht von zwingendenden signifikanten Unterschieden beider Varianten, sondern was im Worst Case passieren sollte.
                            Ich denke nicht, dass der Unterschied bei zwei Mustern, die greifen, als signifikant zu bezeichnen ist. Das müsste allerdings anders aussehen, sobald die Muster keine Treffer erzielen; daher auch das Stichwort Backtracking. Spätestens jedoch bei mehreren Greedy Dots in einem einzigen Muster sind die Unterschiede signifikant (ich bin mal auf eine ModRewrite RewriteRule dieser Art gestoßen: (.*)/(.*)/(.*)/(.*), um mal ein krasses Beispiel zu nennen).

                            Wie gesagt, vielleicht finde ich morgen die Zeit, mal einen kleinen Benchmark zu schreiben.

                            OffTopic:

                            Danke.
                            Ich koche meistens um diese Zeit. Nach einem Spätdienst oder Training bleibt mir nichts anderes übrig.



                            Schönen Abend noch
                            Nieder mit der Camel Case-Konvention

                            Kommentar


                            • #15
                              Nochmal ein paar Worte zum Punkt Greedy Dots versus Negated Character Classes: Dazu möchte ich erklären, wie eine Regex Engine intern einen Greedy Dot abarbeitet und dadurch heraussstellen, weswegen es günstiger sein kann, nach Möglichkeit eine Negated Character Class zu benutzen. Vielleicht für diejenigen interessant, die noch nicht wussten, was da hinter den Kulissen passiert.

                              Ich werde die Erklärungen in Stichpunkten halten, damit kein ellenlanger Text entsteht. Ich hoffe, dass es trotzdem verständlich ist:

                              Beispiel Muster: /(.+)/
                              Beispiel Zeichenkette: /foo/bar
                              • Slash aus Muster trifft auf Slash der Zeichenkette; Ergebnis: [COLOR=crimson]/[/COLOR]
                              • Punkt matcht alle Zeichen, zuallererst ´f´; Ergebnis [COLOR=crimson]/f[/COLOR]
                              • Der Punkt wird intern wiederholt, um auch das nächste Zeichen zu matchen, nun also das ´o´; Ergebnis [COLOR=crimson]/fo[/COLOR]
                              • Punkt wird abermals wiederholt und matcht das nächste ´o´; Ergebnis: [COLOR=crimson]/foo[/COLOR]
                              • Nun zum "Problem": Der Punkt trifft auf das Slash und matcht natürlich auch das, obgleich das zweite Slash in unserem Muster eigentlich das Ende des Ergebnisses demarkiert; Ergebnis: [COLOR=crimson]/foo/[/COLOR]
                              • Der Punkt treibt sein Spiel jetzt aber noch bis zum Ende der Zeichenkette fort, bis er beim letzten Zeichen, dem ´r´, merkt, dass das Muster fehlschlägt.
                              • Erst jetzt geht die Regex Engine einen Schritt weiter und beginnt mit dem nächsten Zeichen aus dem Muster, dem zweiten Slash, das aber nichts matcht, da wir bereits am Ende der Zeichenkette angelangt sind.
                              • Jetzt geht also das Backtracking los.
                              • Das bisherige Ergebnis [COLOR=crimson]/foo/bar[/COLOR] wird um ein Zeichen reduziert; Ergebnis: [COLOR=crimson]/foo/ba[/COLOR]
                              • Das reduzierte `r`passt nicht auf das aktuelle Slash des Musters, also wird weiter gebacktrackt (Copyright by Griecherus ); Ergebnis: [COLOR=crimson]/foo/b[/COLOR]
                              • Selbes Ergebnis wie oben - es wird weiter reduziert; Ergebnis [COLOR=crimson]/foo/[/COLOR]
                              • Erst jetzt greift das Slash aus dem Muster: wir haben unser gewünschtes Ergebnis. /foo/

                              Man sieht also, dass das Muster nur suboptimal abgearbeitet wurde, auch wenn es schlussendlich das erhoffte Ergebnis liefert.

                              Erste Benchmarks bei solchen Minimustern scheinen in der Tat keine signifikanten Unterschiede herauszustellen; die Ergebnisse liegen sogar ziemlich nahe beieinander. Bei komplexeren Mustern oder Mustern, die in Schleifen benutzt werden, könnte oder müsste das bereits anders aussehen - ich habe es selbst allerdings noch nicht getestet. Besonders, wenn die zu durchsuchende Zeichenkette sehr lang ist, kann man sich vorstellen, dass die Regex Engine viel Arbeit umsonst leistet, um sie nachher durchs Backtracking wieder rückgängig zu machen.
                              Und wenn man Ratschlag dadurch nur noch eher theoretischer Natur ist: Regex Engine intern gesehen ist es günstiger, eine Negated Character Class zu benutzen, wo sie sinnvoll eingesetzt werden kann, auch wenn man im Normalfall wohl nicht in Teufels Küche kommen wird, wenn man es nicht tut.

                              Ich hoffe der eine oder andere fands interessant.

                              Grüße

                              Grüße
                              Zuletzt geändert von Griecherus; 27.05.2008, 15:16.
                              Nieder mit der Camel Case-Konvention

                              Kommentar

                              Lädt...
                              X