PlayersGarden: Regulärer Ausdruck / preg_match

Ich habe folgenden String:

{LG:FOO_BAR|Foo|Bar|Foo_Bar}

Ich möchte mit einem Pregmatch die folgende Teile in einem Array haben:
FOO_BAR
Foo
Bar
Foo_Bar

Folgender Code holt mir schon sauber FOO_BAR raus und schreibt es in ein Array mit dem Key 'identifier'.

'/{LG:(?<identifier>[\w]+)([|[A-Za-z0-9]+]*)}/'

Nur bekomm ich irgendwie die N-wiederholbare '|<foo_bar>' Teile nicht extrahiert.

Any Chance?

  1. Hallo PlayersGarden!

    {LG:FOO_BAR|Foo|Bar|Foo_Bar}

    Ich möchte mit einem Pregmatch die folgende Teile in einem Array haben:
    FOO_BAR
    Foo
    Bar
    Foo_Bar

    Any Chance?

    Ob eine (immer etwas mehr Performance kostende) RegExp für eine relativ einfache Aufgabe notwendig ist?

    Ich würde hier (in Perl - da keine PHP-Kenntnissen) mit substr() und split() arbeiten... Bin aber gespannt auf die anderen Vorschläge, die Du bekommst... ;)

    Viele Grüße aus Frankfurt/Main,
    Patrick

    --
    _ - jenseits vom delirium - _

       Diblom   [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
    J'ai 10 ans! | Achtung Agentur! | Nichts ist unmöglich? Doch! | Heute schon gegökt?
  2. Hallo,

    Ich habe folgenden String:

    {LG:FOO_BAR|Foo|Bar|Foo_Bar}

    Ich würde das wie folgt lösen:

      
    $string = "Foo|Foo|Bar|Foo_Bar";  
    $test = explode('|', $string);  
      
    print_r($test);  
    
    

    MfG
    cross

    1. Hallo,

      »» Ich habe folgenden String:
      »»
      »» {LG:FOO_BAR|Foo|Bar|Foo_Bar}

      Shit - nicht aufgepasst, sorry!

        
       $string = "FOO_BAR|Foo|Bar|Foo_Bar";  
       $test = explode('|', $string);  
        
       print_r($test);  
       
      

      MfG
      cross

      1. Da kannst Du auch gleich das vorschlagen:

        $test = array('FOO_BAR', 'Foo', 'Bar', 'Foo_Bar');

        1. Hallöchen auch,

          Da kannst Du auch gleich das vorschlagen:

          $test = array('FOO_BAR', 'Foo', 'Bar', 'Foo_Bar');

          Du scheinst ja ein ganz schlauer zu sein, oder?! Es geht darum einen String zu zerlegen und nicht um von vornherein ein Array zu schreiben. Eine Möglichkeit habe ich mit meinem Beispiel zu "explode" aufgezeigt. Wie der OT das nun für sich nutzt oder auch nicht, ist ihm überlassen.

          MfG
          cross

          1. Eine Möglichkeit habe ich mit meinem Beispiel zu "explode" aufgezeigt.

            Du hast aber einfach einen string(-Ausschnitt) genommen, der sich mit deiner Methode so zerlegen läßt, das hat mehr von einem Ergebnis als von einer Lösung. Wenn Du es für nötig hältst dem Fragesteller explode anhand eines Beispieles nahezubringen, dann müßtest Du es auch für nötig halten ihm zu sagen, mit welchen Mitteln er zu dem string-Ausschnitt kommt.

            1.   
              $pattern = '/\{LG:(?<identifier>[\w]+)\|*(?<elements>(.*?)+)*?\}/s';  
              $string = '<li>{LG:TEASER_TEXT_1|Foo|<input type="button" name="fu" value="Ölapaloma" onclick="alert(\'Das ist ein \\ Test >> //\')"/>|FooBar}</li>';  
              preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);  
              
              

              Auf Elements mach ich nun ein explode und dann hab ich die Teile auch schon in einem Array.

              Meine Vermutung zu meinem anderen RegExp ist, dass er zwar jedes Element findet, aber das Gefundene immer wieder mit dem Nächstgefundenem im Array überschreibt. Ja - ich habe davor natürlich kein ?<elements> benutzt ;)

            2. Hallöchen auch,

              Du hast aber einfach einen string(-Ausschnitt) genommen, der sich mit deiner Methode so zerlegen läßt, das hat mehr von einem Ergebnis als von einer Lösung. Wenn Du es für nötig hältst dem Fragesteller explode anhand eines Beispieles nahezubringen, dann müßtest Du es auch für nötig halten ihm zu sagen, mit welchen Mitteln er zu dem string-Ausschnitt kommt.

              Hmmm ..

              Es war gar nicht angedacht, eine Lösung zu präsentieren, als vielmehr einen Tipp zu geben, es ohne preg_match zu versuchen. preg_match ist imoh für diese Aufgabe viel zu überdimensioniert. Mit 2-3 Zeilen code ist das leicht durchzuführen, als auf dieses mächtige preg_match() zurückzugreifen.

              Wie gesagt - das ist ansichtssache. Alles kann - niemand muss.

              MfG
              cross

  3. Ich habe folgenden String:

    {LG:FOO_BAR|Foo|Bar|Foo_Bar}

    Der String kann auch so aussehen:

    $string= '<div>{LG:FOO_BAR|Foo|Bar|Foo_Bar}</div>';

    Von daher kann ich nicht einfach mit explode() oder substr() arbeiten.

    Ich möchte mit einem Pregmatch die folgende Teile in einem Array haben:
    FOO_BAR
    Foo
    Bar
    Foo_Bar

    Folgender Code holt mir schon sauber FOO_BAR raus und schreibt es in ein Array mit dem Key 'identifier'.

    '/{LG:(?<identifier>[\w]+)([|[A-Za-z0-9]+]*)}/'

    Dort bekomme ich schon in ein anderes Sub-Array "|Foo|Bar|Foo_Bar". Tatsächlich, könnte ich dies per explode() bearbeiten.

    Schöner wäre dennoch ein pregmatch, der mir alles schon fein säuberlich ausliefert. Ich denke bei meinem Ausdruck ist nur noch ein kleiner Fehler.

    1. Der String kann auch so aussehen:

      ...

      Wie wäre es mit einer erschöpfenden Definition von dem was reingehen kann und von dem was rauskommen soll?

      1. Wie wäre es mit einer erschöpfenden Definition von dem was reingehen kann und von dem was rauskommen soll?

        Grundsätzlich könnte der gesamte HTML Code einer Webpage da durchlaufen.

        Für das Sprach-Template-System ist ein String wie folgender vorgesehen:

        {LG:FOO_BAR|foo|bar}

        LG: <- sagt aus, dass er in der DB suchen soll
        FOO_BAR <- ist der Identikator für den Sprachbaustein
        foo und bar sind Elemente, die in den Sprachbaustein eingesetzt werden.

        Beispiel des Sprachbaustein:

        Du hast %1 von %2 Foobars.

        Dann ist %1 = foo und %2 = bar.

          
        /**  
         * This function creates a string consisting of where-clauses of all placeholders found in the string  
         *  
         * @param string $string  
         *  
         * @return string  
         */  
        private function _getWhereSqlString($string) {  
        	$pattern = '/\{LG:(?<identifier>[\w]+)([\|[A-Za-z0-9]+]*)\}/';  
        	$count = preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);  
        	var_dump('<pre>', $match, '</pre>');  
        	$where = '';  
        	if ($count > 0) {  
        		$count_where = 0;  
        		foreach ($matches as $match) {  
        			if ($count_where == 0) { $where .= 'WHERE '; }  
        							else { $where .= ' OR '; }  
        			$where .= 'lg_identifier = \''.$match['identifier'].'\'';  
        			$count_where++;  
        		}  
        	}  
        	return $where;  
        }  
        
        

        Natürlich wird in der Funktion noch keiner der %n Phrasen gespeichert, darum kümmer ich mich dann, wenn ich eine Lösung zum Herausfiltern der Bausteine '|foo' oder '|bar' hab.
        Zuerst will ich in dem Array $match die '|bar' einzeln haben. Natürlich am liebsten ohne '|'.
        Bei dem Beispiel oben entsteht ein multidimensionales Array wo einmal 'FOO_BAR' als value mit dem Key 'identifier' gespeichert wird und ein value wo '|foo|bar' gespeichert wird - mit einem numerischen Key.

          
        array(6) {  
          [0]=>  
          array(4) {  
            [0]=>  
            string(26) "{LG:TEASER_TEXT_1|FOO|BAR}"  
            ["identifier"]=>  
            string(13) "TEASER_TEXT_1"  
            [1]=>  
            string(13) "TEASER_TEXT_1"  
            [2]=>  
            string(8) "|FOO|BAR"  
          }  
        }  
        
        
        1. var_dump('<pre>', $match, '</pre>');

          muss natürlich so sein:

          var_dump('<pre>', $matches, '</pre>');

          1.   
            $pattern = '/\{LG:(?<identifier>[\w]+)(\|[A-Za-z0-9]+)*\}/';  
            $string = '<li>{LG:TEASER_TEXT_1|Foo|Bar|FooBar}</li>';  
            preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);  
            var_dump('<pre>', $matches, '</pre>');  
            
            

            Liefert folgendes Array:
              array(4) {
                [0]=>
                string(33) "{LG:TEASER_TEXT_1|Foo|Bar|FooBar}"
                ["identifier"]=>
                string(13) "TEASER_TEXT_1"
                [1]=>
                string(13) "TEASER_TEXT_1"
                [2]=>
                string(7) "|FooBar"
              }

            Jetzt ist die Frage - wieso nimmt er nur das letzte '|FooBar' Element und nicht alle? Wird das Value evtl. immer überschrieben?

        2. Grundsätzlich könnte der gesamte HTML Code einer Webpage da durchlaufen.

          Für das Sprach-Template-System ist ein String wie folgender vorgesehen:

          {LG:FOO_BAR|foo|bar}

          LG: <- sagt aus, dass er in der DB suchen soll
          FOO_BAR <- ist der Identikator für den Sprachbaustein
          foo und bar sind Elemente, die in den Sprachbaustein eingesetzt werden.

          Was davon soll was identifizieren?

          1. Kommt so ein Gesamtausdruck nur einmal pro zu durchsuchenden sting vor?
          2. Sind FOO_BAR, foo, und bar dadurch gekennzeichnet, daß Du die, die Du haben willst alle kennst?
          3. Kommen überhaupt nur solche vor die Du haben willst?
          4. Soll zwischen Groß- und Kleinschreibung unterschieden werden?
          5. Oder sind sie dadurch gekennzeichnet, daß sie zwischen "{LG:"  und "}" stehen und mit "|" getrennt sind?
          6. ... oder zwischen "{irgendwas:irgendwasanderes|" und ... ?

          Wenn ich dein $pattern anschaue, sind die Antworten offenbar zu 1. keine Ahnung (aber wahrscheinlich egal), zu 2. nein, zu 3. ja (aber egal), zu 4. nein, zu 5. ja und zu 6. nein.

          Wenn die Antwort auf 5. ja lautet, kann man eventuell sagen, daß die Elemente die Du haben willst insgesamt zwischen "{LG:" und "}" stehen und einzeln zwischen ":" oder "|" und "|" oder "}". Ist dem so? Wenn ja, könntest Du mit preg_match_all, look-ahead und look-behind vermutlich zum Ziel kommen. Ich halte eine Folge einfacher Stringfunktionen in dem Fall aber für besser geeignet.

            1. Kommt so ein Gesamtausdruck nur einmal pro zu durchsuchenden sting vor?

            er kommt n-mal vor

            1. Sind FOO_BAR, foo, und bar dadurch gekennzeichnet, daß Du die, die Du

            haben willst alle kennst?
            nein, da kann alles mögliche was in HTML erlaubt ist drin stehn

            1. Kommen überhaupt nur solche vor die Du haben willst?

            egal

            1. Soll zwischen Groß- und Kleinschreibung unterschieden werden?

            nein

            1. Oder sind sie dadurch gekennzeichnet, daß sie zwischen "{LG:"  und "}" stehen und mit "|" getrennt sind?

            der gesuchte String kann so aussehen:

            {LG:foobar}
            {LG:foobar|FOO|BAR}
            {LG:foobar|FOO}
            {LG:foobar|FOO|BAR|foo_bar|FOOBAR_foobar} usw.

            Das was hinter '{LG:' und vor dem ersten (optionalen) '|' steht - also 'foobar' ist der identifier.

            Die n-möglichen pattern nach dem ersten (optionalen) '|' sind sonst wie lang und da kann eine Menge html Zeug drin stehn.

            1. ... oder zwischen "{irgendwas:irgendwasanderes|" und ... ?

            nein

            1. der gesuchte String kann so aussehen:

              {LG:foobar}
              {LG:foobar|FOO|BAR}
              {LG:foobar|FOO}
              {LG:foobar|FOO|BAR|foo_bar|FOOBAR_foobar} usw.

              Welchen Informationsgehlat, glaubst Du, hat das?

              Naja, ein erster ungetesteter Ansatz, zu verwenden in preg_match_all:

              '/(?<={LG)(?::|.*?|)[A-Za-z0-9]+)?(?=|.*?)?(?=})/'

              Etwas vor dem "{LG" gefolgt von ":" oder "irgendwas möglichst kurzes und |" steht und auf daß eventuell "| und irgendwas möglichst kurzes" gefolgt von "}" folgt.

              Der identifier wird hier aber noch nicht besonders behandelt, falls das nötig sein sollte.

              1. Welchen Informationsgehlat, glaubst Du, hat das?

                Mit den Zeilen darunter hatte ich das Gefühl, dass der Informationsgehalt recht hoch ist:

                » {LG:foobar}
                » {LG:foobar|FOO|BAR}
                » {LG:foobar|FOO}
                » {LG:foobar|FOO|BAR|foo_bar|FOOBAR_foobar} usw.

                » Das was hinter '{LG:' und vor dem ersten (optionalen) '|' steht - also 'foobar' ist der identifier.

                » Die n-möglichen pattern nach dem ersten (optionalen) '|' sind sonst wie lang und da kann eine Menge html Zeug drin stehn.

                Pattern sind in dem oben abgebildeten Beispiel: FOO, BAR, foo_bar, FOOBAR_foobar

                1. Mit den Zeilen darunter hatte ich das Gefühl, dass der Informationsgehalt recht hoch ist:

                  Die Zeilen darunter habe ich auch verstanden, sonst hätte ich den Ansatz nicht aufgestellt. Hast Du ihn mal getestet?

                  ... und da kann eine Menge html Zeug drin stehn.

                  [A-Za-z0-9]+ hört sich nicht so an als würde es auf viel html matchen.

                  1. Hast Du ihn mal getestet?

                    Dein $pattern hat mir folgenden Fehler ausgespuckt: Unmatched parentheses

                    [A-Za-z0-9]+ hört sich nicht so an als würde es auf viel html matchen.

                    Ja - ich hatte den Such-String in der Zeit schon mehrfach wieder verändert.

                    Aktuelles Probebeispiel:

                      
                    $string = '<li>{LG:TEASER_TEXT_1|Das ist ein Test|12:42:31|5|˙·٠•● FooBar ●•٠·˙}</li>'  
                    $pattern = '/\{LG:(?<identifier>[\w]+)\|?(?<elements>.*?)?\}/s';  
                    $count = preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);  
                    var_dump('<pre>', $matches, '</pre>');  
                    
                    

                    Das Vardump gibt da aus:

                    array(5) {
                      [0]=>
                      string(79) "{LG:TEASER_TEXT_1|Das ist ein Test|12:42:31|5|˙·٠•● FooBar ●•٠·˙}"
                      ["identifier"]=>
                      string(13) "TEASER_TEXT_1"
                      [1]=>
                      string(13) "TEASER_TEXT_1"
                      ["elements"]=>
                      string(60) "Das ist ein Test|12:42:31|5|˙·٠•● FooBar ●•٠·˙"
                      [2]=>
                      string(60) "Das ist ein Test|12:42:31|5|˙·٠•● FooBar ●•٠·˙"
                    }

                    Jetzt kann ich auf elements ein explode machen und bin schon mal einen Schritt weiter.

                    Meine vorigen $pattern haben einfach nicht funktioniert. Ich denke das dort schon jedes der '|foo_bar' Elemente rausgefiltert wurde, nur hat das neustgefundene das letzte im Array überschrieben.

                    In der Datenbank steht jetzt als identifier: TEASER_TEXT_1

                    Und TEASER_TEXT_1 hat zum Beispiel den deutschsprachigen Wert:

                    "Was haben wir denn hier: %1 um %2 und es wurde %3 von %4 geändert."

                    Dabei soll dann später folgend ersetzt werden:
                    %1 - Das ist ein Test
                    %2 - 12:42:31
                    %3 - 5
                    %4 - ˙·٠•● FooBar ●•٠·˙

                    Aber das sind dann extra Funktionen. Ich wollte nur deutlich machen wofür ich das Brauche. Sprich ist das erste hinter {LG: ein Platzhalter für einen Text, welcher auch Platzhalter enthalten kann, welche dann aber mit %1 gekennzeichnet sind und die später dann mit den Elementen hinter dem ersten Trenner '|' liegen.

                    Ich weiß nicht wie ich es besser beschreiben kann.

                    1. »» Hast Du ihn mal getestet?
                      Dein $pattern hat mir folgenden Fehler ausgespuckt: Unmatched parentheses

                      Und das wars jetzt? Die Fehlerbeschreibung sollte doch wohl einen deutlichen Hinweis liefern wobei ich mich vertippt habe. Ach was soll's, einfach copy and paste -> "(".

                      Jetzt kann ich auf elements ein explode machen und bin schon mal einen Schritt weiter.

                      Nur warum Du so einen Aufwand treibst um ein explode anwenden zu können?

                      1. Und das wars jetzt? Die Fehlerbeschreibung sollte doch wohl einen deutlichen Hinweis liefern wobei ich mich vertippt habe. Ach was soll's, einfach copy and paste -> "(".

                        Natürlich hab ich die Klammer eingefügt Dann kam folgende Fehlermeldung:
                        Nothing to repeat. Was ja auch nicht das Problem war.

                        Nur warum Du so einen Aufwand treibst um ein explode anwenden zu können?

                        Ich verwende den Explode, da ich mit dem Pregmatch nicht voran komme - sprich, die Werte hinter '|' sich immer mit  dem neueren Suchergebnis im $matches Array überschreiben.

                        Ich hatte die Hoffnung, dass ich ein Pregmatch finde, das mir eine ganze Menge HTML Code + den Sprachplatzhalter {LG:<identifier><|phrase1><|phrase2|>} durchsucht und

                        1. den Identifier in dem $matches Array speichert
                        2. und jede phrase in dem $matches Array speichert

                        Vorher hatte ich nur den Identifier: {LG:<<identifier>} ohne die Phrasen. Das war natürlich wesentlich leichter in den Template-HTML String zu finden:

                          
                        $string = '<div>{LG:WARNING_4}';  
                        $pattern = '/\{LG:([A-Z_0-9]+)\}/';  
                        preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);  
                        
                        

                        Ich hab hier eigentlich einen Experten für Reguläre Ausdrücke, nur der kam auch nicht weiter, da die Phrasen sich wohl gegenseitig im $matches Array überschreiben.

                        Mit Look-around assertions hatte ich es auch schon probiert, sprich JEDES Element zwischen '{LG:' und '}' was nach einem '|' kommt zu speichern - aber wieder das gleiche, nur die letzte Phrase wurde im Array gespeichert. Was die Vermutung, dass sie sich gegenseitig überschreiben, unterstützt.

                        1. »» Und das wars jetzt? Die Fehlerbeschreibung sollte doch wohl einen deutlichen Hinweis liefern wobei ich mich vertippt habe. Ach was soll's, einfach copy and paste -> "(".

                          Natürlich hab ich die Klammer eingefügt Dann kam folgende Fehlermeldung:
                          Nothing to repeat. Was ja auch nicht das Problem war.

                          "Hier bezieht sich der Quantifer lediglich auf die Assertion ... was nicht erlaubt ist."

                          Das wußte ich noch nicht. Aus deiner Mitteilsammkeit schließe ich nun, daß es jetzt geht oder nicht.

                          Ich hab hier eigentlich einen Experten für Reguläre Ausdrücke, nur der kam auch nicht weiter, da die Phrasen sich wohl gegenseitig im $matches Array überschreiben.

                          Mit Look-around assertions hatte ich es auch schon probiert, sprich JEDES Element zwischen '{LG:' und '}' was nach einem '|' kommt zu speichern - aber wieder das gleiche, nur die letzte Phrase wurde im Array gespeichert. Was die Vermutung, dass sie sich gegenseitig überschreiben, unterstützt.

                          Wenn Du auch versuchst mehrere Treffer auf einen Teilausdruck in einem Arrayelement zu speichern. Was bei der Strategie look-around assertions bringen sollen kann ich nicht erkennen, aber egal. Jeder Teilausdruck mit einfachen Klammern wie (xyz) wird in einem Arrayelement gespeichert, wenn man nun (xyz)* schreibt, kann immer noch nur der Teilausdruck in einem Arrayelement gespeichert werden. Du muß versuchen alles was Du haben willst einzeln als kompletten Ausdruck zu erhalten. Mit Teilausdrücken würdest Du nur zum Ziel kommen, wenn Du weißt wie viele Treffe innerhalb von '{LG:' und '}' (maximal) zu erwarten sind.

  4. Nur bekomm ich irgendwie die N-wiederholbare '|<foo_bar>' Teile nicht extrahiert.

    Was auch immer das heißen soll und was auch immer "<" und ">" dort zu suchen haben, eventuell mußt Du preg_match_all nehmen.