hawkmaster: Regex Problem mit Oder Verknüpfung

Hallo zusammen,
ich suche in einem String nach allen Vorkommen wie;

$var_1
$var_23
$var_456

Es gibt also immer die Zeichenfolge "$var_" gefolgt von 1-3 Zahlen
Soweit habe ich es hinbekommen.

if (preg_match_all('#$var_[0-9]{1,3}#', $string, $contents)){

Jetzt kommen aber noch ein paar wenige Variablen mit der Schreibweise:

$var_1_1
$var_456_6

also wie vorher nur mit zusätzlichen "_" (Unterstrich) gefolgt von einer Zahl
Auch das alleine würde ich hinbekommen:

if (preg_match_all('#$var_[0-9]{1,3}_[0-9]{1}#', $string, $contents)){

Ich würde dies nun gerne in eine einzige Regex unterbringen mit einer ODER Verknüpfung. Hier komme ich jedoch nicht so recht weiter.
Ich habe es so versucht:

if (preg_match_all('#($var_[0-9]{1,3})|($var_[0-9]{1,3}_[0-9]{1})#', $string, $contents)){

Die Ausgabe mit print_r($contents) bringt mir immer nur die Werte von der ersten Abfrage dafür aber doppelt.
Was mache ich falsch?

vielen Dank und viele Grüße
hawk

  1. if (preg_match_all('#$var_[0-9]{1,3}#', $string, $contents)){
    if (preg_match_all('#$var_[0-9]{1,3}_[0-9]{1}#', $string, $contents)){

    Was mache ich falsch?

    DU machst einen logischen Fehler ;)

    Du willst $var_123 finden und $var_124_1

    Also deinen ersten Ausdruck gefolgt von der ergänzung, aber optional: du suchst "?" sowie subpatterns

    \d entspricht übrigens [0-9]

    1. if (preg_match_all('#$var_[0-9]{1,3}#', $string, $contents)){
      if (preg_match_all('#$var_[0-9]{1,3}_[0-9]{1}#', $string, $contents)){

      Du willst $var_123 finden und $var_124_1
      Also deinen ersten Ausdruck gefolgt von der ergänzung, aber optional: du suchst "?" sowie subpatterns

      #(x(?:y)?)#
      ist nicht zielführend in diesem Fall.
      Allenfalls brauchst du negative lookaheadsm was das Ganze aber komplexer macht.
      Dein Rezept trifft nur zu wenn dieser Fall zutrifft:
      #(x(?:y)?)z#

      Aber Umstellen ist einfacher
      #(xy|x)#

      mfg Beat

      --
      ><o(((°>           ><o(((°>
         <°)))o><                     ><o(((°>o
      Der Valigator leibt diese Fische
      1. #(x(?:y)?)#

        Ja, non-capturing parenthesis machen auch gebrauch von Klammer und Fragezeichen ;)

        ist nicht zielführend in diesem Fall.

        Das sagte ich auch nicht

        Allenfalls brauchst du negative lookaheadsm was das Ganze aber komplexer macht.

        Warum so kompliziert?

        Aber Umstellen ist einfacher
        #(xy|x)#

        Das bringt im genannten fall garnichts.

  2. Ich habe es so versucht:
    if (preg_match_all('#($var_[0-9]{1,3})|($var_[0-9]{1,3}_[0-9]{1})#', $string, $contents)){

    Die Ausgabe mit print_r($contents) bringt mir immer nur die Werte von der ersten Abfrage dafür aber doppelt.
    Was mache ich falsch?

    Es wird immer nach der ersten Möglichkeit in einem (|) gesucht, nis diese versagt. Die versagt hier aber nicht.

    Du musst deshalb die Reihenfolge umstellen.

    #$var_(\d{1,3}_\d|\d{1,3})#

    Versagt die erste Variante, wird die zweite verwendet.

    mfg Beat

    --
    Surftipp:
    Die NATO
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
    1. #$var_(\d{1,3}_\d|\d{1,3})#

      Fürchterlich - ich würd's damit versuchen.

      #$var_\d{1,3}(_\d)?#

    2. Hallo

      herzlichen Dank für eure tolle Hilfe.

      Du musst deshalb die Reihenfolge umstellen.

      #$var_(\d{1,3}_\d|\d{1,3})#

      Versagt die erste Variante, wird die zweite verwendet.

      Ok, jetzt ist es klar. Das versteh ich noch :-)
      Das hier gerade auch noch:
      #$var_\d{1,3}(_\d)?#
      Ich versuches mal in meinem laienhaften regex Verständnis zu erklären.

      \d{1,3}  = Zahlen, mindestens 1, maximal 3

      (_\d)? bedeutet wegen dem Fragezeichen "einmal oder keinmal" und \d reicht auch weil ja immer nur eine Zahl. Man braucht also gar keine "Oder" Verknüpfung?

      Eure restlichen Ergüsse wie
      "Allenfalls brauchst du negative lookaheadsm was das Ganze aber komplexer macht."
      oder
      "Ja, non-capturing parenthesis machen auch gebrauch von Klammer und Fragezeichen ;)"

      muss man ja nicht sofort verstehen oder :-))

      vielen Dank und viele Grüße
      hawk

      1. Das hier gerade auch noch:
        #$var_\d{1,3}(_\d)?#
        Ich versuches mal in meinem laienhaften regex Verständnis zu erklären.

        \d{1,3}  = Zahlen, mindestens 1, maximal 3

        Ja, \d ist gleichbedeutend zu [0-9]

        (_\d)? bedeutet wegen dem Fragezeichen "einmal oder keinmal" und \d reicht auch weil ja immer nur eine Zahl. Man braucht also gar keine "Oder" Verknüpfung?

        \d alleine reicht nicht, du willst da $var_123__1 oder $var_123__2 finden - wenn du \d alleine notierst und den _ vorher schon dranpackst, würdest du auch $var_123_ finden, nicht nur $var_123.

        Eure restlichen Ergüsse wie
        "Allenfalls brauchst du negative lookaheadsm was das Ganze aber komplexer macht."

        Ignorieren, braucht man sehr selten und sind wirklich sehr komplex und schwierig zu verstehen.

        "Ja, non-capturing parenthesis machen auch gebrauch von Klammer und Fragezeichen ;)"

        gewöhnlich: #$var_\d{1,3}(_\d)?#
        mit non-capturing parenthesis: #$var_\d{1,3}(?:_\d)?#

        Wenn du dir das Array (bzw. beide) ansiehst, welches von preg_match_all produziert wird, wirst du den Unterschied schnell verstehen.

        In deinem Fall ist es imho egal ob du ?: zusätzlich notierst oder nicht da du das Subpattern nur als Mittel zum Zweck verwendest im das _\d gemeinsam als optional zu kennzeichnen.

        1. Hallo

          danke nochmals für die gute Erklärung:

          Noch was. Ich will deswegen keinen neuen Thread aufmachen weil es indirekt mit dem zusammenhängt.
          Ich habe nun also alle Vorkommen von

          "$var_" gefunden. Ich speichere alles in einem Array.
          z.b. steht in dem Array
          $var_123
          $var_10
          ..

          In einer PHP Datei die ich inkludiere stehen diese Variablen wie folgt:

          $var_123 = "Das ist ein Text";
          $var_10 = "Noch ein Text";

          Ich würde nun gerne mit Hilfe der vorherigen Suche alle Strings ausgeben.
          Würde sich hier wiederum eine neue Suche mit Regex anbieten oder gibt es hier vielleicht einfachere PHP Funktionen?

          vielen Dank und viele Grüße
          hawk

          1. Hi!

            Ich würde nun gerne mit Hilfe der vorherigen Suche alle Strings ausgeben.
            Würde sich hier wiederum eine neue Suche mit Regex anbieten oder gibt es hier vielleicht einfachere PHP Funktionen?

            Das hört sich so an, als ob das eigentliche Problem wesentlich eleganter zu lösen ist, wenn man es anders anpackt, du dich jedoch gerade in eine Situation hineinprogrammiert hast, wo du nur noch mit Klimmzügen weiterkommst.

            Der andere Weg wäre vielleicht statt der durchnummerierten Variablen ein Array zu verwenden. Auf Array-Elemente kann man wesentlich einfacher zugreifen als auf einen Haufen rumliegender Variablen.

            Wenn der Array-Weg nicht geht, wäre für deine Situation vielleicht dieser Vorschlag angemessen:

            In einer PHP Datei die ich inkludiere stehen diese Variablen wie folgt:
            $var_123 = "Das ist ein Text";
            $var_10 = "Noch ein Text";

            Stehen in der PHP-Datei nur solche Variablenzuweisungen? Dann würde ich sie innerhalb einer Funktion inkludieren, damit diese Variablen nicht im globalen Scope rumlungern sondern nur in funktionslokalen. Das Array mit den gefundenen Werten lässt sich als Parameter übergeben. Aus diesen Werten  kannst du variable Variablen bilden, mit isset() ihre Existenz prüfen und dann wie gewünscht drauf zugreifen, beispielsweise die Texte in einem Array sammeln, das die Funktion zurückgeben kann.

            Lo!

            1. Hallo dedlfix,
              danke für deine Ratschläge,

              ok, mal kurz was zu meinem Vorhaben:
              Es geht um "Altlasten" bereinigen.

              Ich habe eine Webanwendung in der Sprachdateien inkludiert wurden.
              z.b. "english.php" hatte dann:
              $var_1 = "Hello User";

              In der Anwendung wurde nun über all mit den Variablen gearbeitet. Also etwa;
              echo $var_1;

              Ich möchte nun diese alte Sprachdateien ablösen und alles in eine Datenbank bringen.
              Da alles von Hand suchen und eintragen recht mühsam ist, versuche ich mir ein wenig die Arbeit abzunehmen indem ich das automatisiere.
              Daher zuerst meine Suche nach allen Sprachvariablen in allen PHP Dateien.
              Dann könnte ich weiter machen indem ich die entsprechenden Übersetzungen finde und in die DB eintrage.
              Zu guter Letzt müsste ich dann halt noch die ganzen "$var_" ersetzen mit den entsprechenden Datenbank IDs.

              ich bin aber für alle besseren Ideen offen :-)

              vielen Dank und viele Grüße
              hawk

              1. Hi!

                ok, mal kurz was zu meinem Vorhaben:
                Es geht um "Altlasten" bereinigen.
                [...]

                Es handelt sich also um einen einmaligen Vorgang, dessen Ziel es ist, sowieso das kaputte System abzulösen/zu reparieren? Dann reicht es ja, wenn du das Ziel erreichst. Auf Schönheit kann dabei verzichtet werden, weil der Code am Ende entsorgt wird.

                Den von mir vorgeschlagenen Weg mit der Funktion, sehe ich dafür angemessen zu sein. Selbst parsen ist unnötig aufwendig, weil du dabei quasi alle syntaktischen Möglichkeiten berücksichtigen müsstest. Ein String hört auf ' .
                'und wird in der nächsten Zeile fortgesetzt, ist dabei noch das kleinste Problem. Deswegen kein Regexp sondern include und die Arbeit dem PHP-Parser überlassen, der kann das schon und muss das nicht erst noch beigebracht bekommen.

                Lo!

                1. Hallo

                  Deswegen kein Regexp sondern include und die Arbeit dem PHP-Parser überlassen, der kann das schon und muss das nicht erst noch beigebracht bekommen.»»

                  Hmm, irgendwie kann ich dir nicht ganz folgen.
                  Ich inkludiere doch schon die Sprachdateien damit ich die Variablen ausgeben kann.
                  Es geht mir doch nun darum die dazugehörigen Strings (Übersetzungen) in die Datenbank zu bringen. Und in den alten Sprachdateien stehen auch viel mehr Strings drin als benötigt.

                  vielen Dank und viele Grüße
                  hawk

                  1. Hi!

                    Deswegen kein Regexp sondern include und die Arbeit dem PHP-Parser überlassen, der kann das schon und muss das nicht erst noch beigebracht bekommen.
                    Hmm, irgendwie kann ich dir nicht ganz folgen.
                    Ich inkludiere doch schon die Sprachdateien damit ich die Variablen ausgeben kann.

                    Gut, dann liegen sie also schon (im globalen Scope) rum. Dann musst du nur noch darauf zugreifen. Ihre Namen hast du mit dem ersten Teil der Frage ja schon ermittelt und muss nur noch von den Namen auf die entsprechende Variable kommen, damit du ihren Inhalt lesen kannst. Das geht mit variablen Variablen, ohne dass du noch weitere RegExps benötigst.

                    Lo!

      2. Hi,

        \d{1,3}  = Zahlen, mindestens 1, maximal 3

        nein, nicht Zahlen. Ziffern!

        Achte bitte auf den Unterschied, weil er gerade im Zusammenhang mit solchen Geschichten leicht zu Missverständnissen führen kann. Eine Zahl besteht im Regelfall aus mindestens einer Ziffer, optional noch einem Vorzeichen, einem Dezimalpunkt - und wenn wir die wissenschaftliche Notation oder Späße wie hexadezimale Schreibweise noch dazunehmen, kann eine Zahl noch viel mehr enthalten.

        Ciao,
         Martin

        --
        Der Sinn einer Behörde besteht in ihrer Existenz.
          (alte Beamtenweisheit)
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        1. \d{1,3}  = Zahlen, mindestens 1, maximal 3

          nein, nicht Zahlen. Ziffern!

          Und in diesem Kontext sogar nur dezimale Ziffern - was natürlich zwangsläufig auch Zahlensysteme abdeckt, die dieselben Ziffern verwenden aber nicht den vollen Umfang ausschlöpfen - z.B. das Oktal- oder Binärsystem.

          Römische Ziffern oder die "Ziffern" A bis F im Hexadezimalsystem sind von \d nicht abgedeckt.

          1. Hi,

            ausschlöpfen

            nett, gefällt mir! :-)
            Best of Typo, Folge 74.

            Römische Ziffern oder die "Ziffern" A bis F im Hexadezimalsystem sind von \d nicht abgedeckt.

            An römische Ziffern (werden die wirklich so genannt?) habe ich gar nicht gedacht; dass man im Hexadezimalsystem aber auch A..F als Ziffern bezeichnet, habe ich jetzt bewusst unterschlagen.

            Ciao,
             Martin

            --
            F: Was ist wichtiger: Die Sonne oder der Mond?
            A: Der Mond. Denn er scheint nachts. Die Sonne dagegen scheint tagsüber, wenn es sowieso hell ist.
            Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
            1. An römische Ziffern (werden die wirklich so genannt?)

              Ja ;)

  3. Hallo zusammen,

    ich hoffe in den alten Thread schaut noch jemand rein :-)
    Ich möchte aber nicht extra einen neuen aufmachen.

    Folgendes:
    Ich versuche Variablen Namen in einem String zu ersetzten.
    z.b. aus $var_3 soll $text[245] werden.

    Ich versuche es so:
    In "$searchvar" steht dann also z.b. $var_3 drin.

    $newstring = preg_replace('#\'.$searchvar.'#', $textidname, $string1);

    Die Ersetzung klappt, aber es wird teilweise zu viel ersetzt. Gefunden bzw. ersetzt werden auch die Variabelen $var_310 oder $var_37

    Ich habe versucht mit dem Modifier U auf nicht gierig umzuschalten.
    $newstring = preg_replace('#\'.$searchvar.'#U', $textidname, $string1);

    Das Ergebnis war aber gleich.

    Kann mir jemand weiter helfen?

    vielen Dank und viele Grüße
    hawk

    1. Hi!

      z.b. aus $var_3 soll $text[245] werden.
      In "$searchvar" steht dann also z.b. $var_3 drin.
      $newstring = preg_replace('#\'.$searchvar.'#', $textidname, $string1);
      Die Ersetzung klappt, aber es wird teilweise zu viel ersetzt. Gefunden bzw. ersetzt werden auch die Variabelen $var_310 oder $var_37

      Ja, denn das passt ja auch auf das Suchmuster. Das Ergebnis ist aber $textidname . '10 ...', also wird nur der Teil bis zur 3 ausgetauscht, ergo auch nur der gefunden.

      Du willst aber nur das finden, was nach dem 3 mit einem Whitespace oder = oder Nicht-Wort-Zeichen oder was auch immer weitergeht, wobei du das Zeichen wiederum vom Ergebnis ausschließen willst. Also vielleicht eine Non-capturing Group oder mit einer Assertion probieren.

      Ich habe versucht mit dem Modifier U auf nicht gierig umzuschalten.

      Das bringt nichts, weil du kein Joker- mit Wiederholungszeichen verwendest, der gierig sein könnte.

      Lo!