RuD: Regulärer Ausdruck für Links

Seid gegrüßt!
Ich versuche mich jetz schon ne Weile an einem Regulärem Ausdruck und komm irgendwie ne weiter:
und zwar will ich an bestehende Links die SESSIONID anfügen. Ich bin bis jetz darauf gekommen:

preg_replace('/<a href="([a-zA-z.?=]{1,})?">/',
             '<a href="$1&_authsession='.$_SESSION[_authsession][challengekey].'">',
             $tpl_source);

das funtioniert aber nur bei Links die schon ne Parameter haben (wegen dem & oder ?)

Wie kann ich beide Varianten (mit und ohne vorherigen Parameter) in einen Regex packen?

--
Bis Später
    
________________________________________________________________
[Testversion meiner Seite] [Zwei unterwegs in Australien]
  1. Lieber RuD,

    ich schlafe zwar schon fast, aber ich würde es simpler gestalten:

    $tpl_source = preg_replace('~(<a href=".*[^?]+)(?:\?([^"]+))?"~', '\\1?\\2&amp;'.SID, $tpl_source);

    1. Parenthese enthält den Link mit Pfad (wird "behalten", ist \1)
    2. Parenthese enthält den Search-String (wird wegen '?:' "vergessen")
    3. Parenthese enthält den Inhalt des Search-Strings (wird "behalten", ist \2)
    SID ist eine Konstante in PHP, die sowohl den Namen, als auch die ID der Session fix unde fertig für die URL enthält.

    • ungeprüft -

    Liebe Grüße aus Ellwangen,

    Felix Riesterer.

    1. Seid gegrüßt!

      Ich danke dir erstmal für deine Antwort:
      Ich will aber nicht nur kopieren sondern auch kapieren (tolles Wortspiel, oder?)

      Also habe ich da noch ein par Fragen:

        
      $tpl_source = preg_replace('  
        ~(<a href="        // was macht die Tilde da? Den Anfang markieren?  
         .*                // Ist klar: Alle Zeichen, egal wieviele  
         [^?]+)            // Hier komm ich nicht mit  
        (?:\?([^"]+))?"~', // Und hier ist alles zu spät  
        
       '\\1?\\2&amp;'.SID, $tpl_source);  
                           // Ja und die Ersetzungen und der Schluß sind klar  
      
      
      1. Parenthese enthält den Link mit Pfad (wird "behalten", ist \1)

      Ist klar.

      1. Parenthese enthält den Search-String (wird wegen '?:' "vergessen")

      Siehe oben

      1. Parenthese enthält den Inhalt des Search-Strings (wird "behalten", ist \2)

      Die ganze Kombination kapier ich nicht

      SID ist eine Konstante in PHP, die sowohl den Namen, als auch die ID der Session fix unde fertig für die URL enthält.

      Ja eigentlich weis ich das auch, nur das Anwenden des Wissens erfolgen maches mal ein wenig "anders".

      • ungeprüft -

      Vielen Dank trotzdem.

      --
      Bis Später
          
      ________________________________________________________________
      [Testversion meiner Seite] [Zwei unterwegs in Australien]
      1. Seid gegrüßt!

        • ungeprüft -

        Funktioniert leider nicht. Um villeich noch ein paar mehr Informationen nachzuschieben: Ich will ein mit Smarty eingebundeses Template über einen Filter so bearbeiten, dass, wenn der User angemeldet ist, der Filter ausgelöst wird und alles Links auf der Seite am Ende noch die SessionID angehängt haben.

        Aber ich kann deine Hilfe nur bedingt versuchen zu bearbeiten weil ich (s.o.) manches nicht ganz verstehe.

        Regex ist ist aber auch ein hartes Thema!

        --
        Bis Später
            
        ________________________________________________________________
        [Testversion meiner Seite] [Zwei unterwegs in Australien]
        1. Moin!

          Ich kann nur perl beisteuern, aber wenn Dir die Ausgabe gefällt, dann kann das bestimmt jemand in PHP umsetzen:

          while (<DATA>) {  
           s/(<a\b[^>]+\bhref="[^"?]+)\??([^"]*)"/$1?$2&sessionid=irgendwas/;  
           print;  
          }  
          __DATA__  
          <a href="http:///twts">  
          <a href="http:///twts?test=123">  
          <a href="http:///twts?test=123&xxxx=234">  
          
          

          Das liefert:

          <a href="http:///twts?&sessionid=irgendwas>
          <a href="http:///twts?test=123&sessionid=irgendwas>
          <a href="http:///twts?test=123&xxxx=234&sessionid=irgendwas>

          Ich dene so ein "?&" sollte nicht stören.

          -- Skeeve

          1. Lieber Skeeve,

            Ich dene so ein "?&" sollte nicht stören.

            also mich stört das schon. Ein "?&amp;" dagegen würde mich nicht stören...

            Liebe Grüße aus Ellwangen,

            Felix Riesterer.

        2. hi,

          Ich will ein mit Smarty eingebundeses Template über einen Filter so bearbeiten, dass, wenn der User angemeldet ist, der Filter ausgelöst wird und alles Links auf der Seite am Ende noch die SessionID angehängt haben.

          Und da ist der Automatismus, den PHP anbietet, nicht nutzbar?

          gruß,
          wahsaga

          --
          /voodoo.css:
          #GeorgeWBush { position:absolute; bottom:-6ft; }
          1. Seid gegrüßt!

            Und da ist der Automatismus, den PHP anbietet, nicht nutzbar?

            Kannst du evtl noch mehr Details liefern?

            --
            Bis Später
                
            ________________________________________________________________
            [Testversion meiner Seite] [Zwei unterwegs in Australien]
            1. hi,

              Und da ist der Automatismus, den PHP anbietet, nicht nutzbar?
              Kannst du evtl noch mehr Details liefern?

              http://www.php.net/manual/de/ref.session.php#session.idpassing, sowie vorherige Beschreibung der Optionen session.use_trans_sid und url_rewriter.tags.

              gruß,
              wahsaga

              --
              /voodoo.css:
              #GeorgeWBush { position:absolute; bottom:-6ft; }
      2. Lieber RuD,

        reguläre Muster in PHP brauchen einen Delimiter. Das ist das erste Zeichen, das den Anfang markiert, und das logischerweise auch am Ende wieder stehen muss. Da ich den Slash (/) in Pfaden nicht aufwendig escapen will, bin ich auf das von mir sonst in Strings am seltensten verwendete Zeichen umgestiegen. Daher sehen Muster bei mir immer so aus:

        preg_xyz('~...muster...~' ...)

        [code lang=php]
        $tpl_source = preg_replace('
          ~(<a href="        // was macht die Tilde da? Den Anfang markieren?
           .*                // Ist klar: Alle Zeichen, egal wieviele
           [^?]+)            // Hier komm ich nicht mit

        Das ist eine Character Class. Sie bedeutet: Ein Zeichen dessen, was in den eckigen Klammern steht. Wenn ein Zirkumflex (oder wie das Dach da heißt) in einer Character Class enthalten ist, dann negiert es ihre Bedeutung. Hier bedeutet sie nun "ein Zeichen, das kein Fragezeichen ist". Das Pluszeichen nimmt davon so viele, wie es kriegt, aber mindestens eines. Dein Pfad besteht doch aus mindestens einem Nicht-?-Zeichen, oder?

        (?:?([^"]+))?"~', // Und hier ist alles zu spät

        Diese Parenthese (äußeres Klammernpaar) soll nicht "gemerkt" werden, denn ich will ja eigentlich nur die innere Klammer haben, daher (?: ... ), denn sonst stünde im Ersetzungsstring später ein "\1" und ein "\3", aber kein "\2" - klar?
        Jetzt will ich als erstes ein echtes Fragezeichen haben. Das ist aber mit einer Sonderbedeutung belegt. Deshalb muss ich für ein echtes Fragezeichen dieses mittels Backslash escapen. Daher steht hier ?, klar?
        In der Klammer will ich alle Zeichen, die keine doppelten Anführungszeichen sind, also wieder eine negierte Character Class. Im Klartext will ich also alles zwischen (?) und ("), nämlich den Search-String. Klar soweit?
        Und jetzt kommt's: Das alles könnte da im Link auch garnicht stehen, denn manche Links haben ja keinen Search-String! Deshalb ist diese Klammer mit dem nicht-merken-Schalter optional, also mit einem nachfolgenden Fragezeichen (welches ganz genau betrachtet "einmal oder kein mal" bedeutet) versehen.

        Die ganze Kombination kapier ich nicht

        Bei weiteren Fragen kommst Du wieder! Aber ich hätte da einen Linktipp für Dich: http://www.regular-expressions.info

        Vielen Dank trotzdem.

        Gern geschehen!

        Liebe Grüße aus Ellwangen,

        Felix Riesterer.

        1. Seid gegrüßt!

          Danke dass du dir die Ziet nimmst mir das zu erklären.

          reguläre Muster in PHP brauchen einen Delimiter. Das ist das erste Zeichen, das den Anfang markiert, und das logischerweise auch am Ende wieder stehen muss.

          Gut, das wusste ich, dass Delimiter gestezt werden müssen. Mir sind blos selbstdefinierte unbekannt.

          [code lang=php]
          $tpl_source = preg_replace('
            ~(<a href="        // was macht die Tilde da? Den Anfang markieren?

          // OK, jetz klar!

          .*                // Ist klar: Alle Zeichen, egal wieviele
             [^?]+)

          // also NICHT ein oder mehrere Fragezeichen, wieso ist das nicht escaped?

          Das ist eine Character Class. Sie bedeutet: Ein Zeichen dessen, was in den eckigen Klammern steht. Wenn ein Zirkumflex (oder wie das Dach da heißt) in einer Character Class enthalten ist, dann negiert es ihre Bedeutung. Hier bedeutet sie nun "ein Zeichen, das kein Fragezeichen ist". Das Pluszeichen nimmt davon so viele, wie es kriegt, aber mindestens eines. Dein Pfad besteht doch aus mindestens einem Nicht-?-Zeichen, oder?

          Ja tut er ;-)

          (?:?([^"]+))?"~', // Und hier ist alles zu spät

          Hier will ich mal von innen anfangen:
            [^"]+                 // wie oben: NICHT ein oder mehrere " (?)
            ?                    // davor ein Fragezeichen
            das ? am Ende         // macht das ganze zur später wieder einzufügenden "Varbiable"

          (?:...)               // ich habs noch nicht geschnallt
                                  // was genau wird vergessen

          Diese Parenthese (äußeres Klammernpaar) soll nicht "gemerkt" werden, denn ich will ja eigentlich nur die innere Klammer haben, daher (?: ... ), denn sonst stünde im Ersetzungsstring später ein "\1" und ein "\3", aber kein "\2" - klar?

          Nicht wirklich .-(

          Jetzt will ich als erstes ein echtes Fragezeichen haben. Das ist aber mit einer Sonderbedeutung belegt. Deshalb muss ich für ein echtes Fragezeichen dieses mittels Backslash escapen. Daher steht hier ?, klar?
          In der Klammer will ich alle Zeichen, die keine doppelten Anführungszeichen sind, also wieder eine negierte Character Class. Im Klartext will ich also alles zwischen (?) und ("), nämlich den Search-String. Klar soweit?

          Teils teils....

          Und jetzt kommt's: Das alles könnte da im Link auch garnicht stehen, denn manche Links haben ja keinen Search-String! Deshalb ist diese Klammer mit dem nicht-merken-Schalter optional, also mit einem nachfolgenden Fragezeichen (welches ganz genau betrachtet "einmal oder kein mal" bedeutet) versehen.

          Die ganze Kombination kapier ich nicht

          Bei weiteren Fragen kommst Du wieder! Aber ich hätte da einen Linktipp für Dich: http://www.regular-expressions.info

          Schöne Seite, sehr ausführlich aber ENGLISH, gibt es eine eben so gute deutsch Seite!

          --
          Bis Später
              
          ________________________________________________________________
          [Testversion meiner Seite] [Zwei unterwegs in Australien]
          1. Lieber RuD,

            [^?]+)
                                    // also NICHT ein oder mehrere Fragezeichen, wieso ist das nicht escaped?

            In einer Character Class haben nur noch zwei Zeichen besondere Bedeutung: die schließende eckige Klammer (sie schließt die Character Class wieder) und das Zirkumflex (es negiert die CC). Der Punkt ist nur noch ein Punkt, eine Klammer ist nur noch eine Klammer (und keine Parenthese mehr), ein Sternchen ist nur noch ein Sternchen usw.

            (?:?([^"]+))?"~', // Und hier ist alles zu spät

            Hier will ich mal von innen anfangen:
              [^"]+                 // wie oben: NICHT ein oder mehrere " (?)

            Nein! So viele nicht-"-Zeichen wie möglich.

            ?                    // davor ein Fragezeichen

            Stimmt.

            das ? am Ende         // macht das ganze zur später wieder einzufügenden "Varbiable"

            Nein, es bedeutet, dass die komplette Parenthese auch komplett entfallen darf, damit der Ausdruck trotzdem noch matcht (für Links ohne Search-String).

            (?:...)               // ich habs noch nicht geschnallt
                                    // was genau wird vergessen

            Alles darin!

            Beispiel:

            preg_match('~(abc)def(?:ghij)?~', 'abcdefxyz') // true, \\1=abc \\2 existiert nicht wegen ?:  
            preg_match('~(abc)def(?:ghij)?~', '_abcdefghijxyz') // true, \\1=abc \\2 existiert nicht
            

            Den Inhalt der ersten Parenthese (Klammernpaar) kann ich per \1 wieder referenzieren, den Inhalt der zweiten Parenthese kann ich _nicht_ referenzieren, da sie "vergessen" wird.

            denn sonst stünde im Ersetzungsstring später ein "\1" und ein "\3", aber kein "\2" - klar?
            Nicht wirklich .-(

            Beispiel:

            preg_match('a(bc)d(ef(gh))?', 'xabcdefghuvw') // true, \\1=bc, \\2=efgh \\3=gh  
            preg_match('a(bc)d(?:ef(gh))?', 'xabcdefghuvw') // true, \\1=bc, \\2=gh \\3 existiert nicht  
            preg_match('a(bc)d(?:ef(gh))?', 'xabcduvw') // true, \\1=bc, \\2= \\3 existiert nicht
            

            Jetzt zu unserem Fall:
            $tpl_source = preg_replace('~(<a href=".*[^?]+)(?:\?([^"]+))?"~', '\\1?\\2&amp;'.SID, $tpl_source);

            Im Ersetzungsstring wollte ich kein \3 verwenden. Aber es hätte auch so funktionieren sollen:
            $tpl_source = preg_replace('~(<a href=".*[^?]+)(\?([^"]+))?"~', '\\1?\\3&amp;'.SID, $tpl_source);

            Ich ignoriere einfach, dass da noch eine weitere Parenthese (\2) gefunden wurde, daher steht jetzt in meinem Ersetzungsstring "\1\3". Ob ich meinen Code später in ein paar Monaten aber überhaupt noch verstehe... Da denke ich, dass es leichter fällt, wenn da "\1\2" steht.

            Außerdem braucht PHP dann weniger Resourcen; es ist sparsamer. Bei komplexeren RegExen kann das schon zu spürbaren Performance-Verlusten führen, wenn man unbenötigte Parenthesen trotzdem "merken" lässt.

            Jetzt will ich als erstes ein echtes Fragezeichen haben. Das ist aber mit einer Sonderbedeutung belegt. Deshalb muss ich für ein echtes Fragezeichen dieses mittels Backslash escapen. Daher steht hier ?, klar?
            In der Klammer will ich alle Zeichen, die keine doppelten Anführungszeichen sind, also wieder eine negierte Character Class. Im Klartext will ich also alles zwischen (?) und ("), nämlich den Search-String. Klar soweit?
            Teils teils....

            preg_match('~ab?~', '_acde') // true, denn b soll keinmal oder einmal vorkommen  
            preg_match('~ab?~', '_abcde') // true  
              
            preg_match('~(gute)? miene~', 'er machte gute miene zum bösen spiel') // true, \\1=gute  
            preg_match('~(gute)? miene~', 'er machte keine miene zum bösen spiel') // true, \\1=
            

            http://www.regular-expressions.info
            Schöne Seite, sehr ausführlich aber ENGLISH, gibt es eine eben so gute deutsch Seite!

            Also ich kenne keine (brauche auch keine)... Aber was stört Dich am Englischen?

            Liebe Grüße aus Ellwangen,

            Felix Riesterer.

            1. hi,

              In einer Character Class haben nur noch zwei Zeichen besondere Bedeutung: die schließende eckige Klammer (sie schließt die Character Class wieder) und das Zirkumflex (es negiert die CC).

              Wenn der Backslash eckige Klammer oder Zirkumflex maskieren soll, muss er dafür aber auch Sonderbedeutung haben ;-)

              gruß,
              wahsaga

              --
              /voodoo.css:
              #GeorgeWBush { position:absolute; bottom:-6ft; }
              1. Lieber wahsaga,

                Wenn der Backslash eckige Klammer oder Zirkumflex maskieren soll, muss er dafür aber auch Sonderbedeutung haben ;-)

                stimmt, hier war ich ungenau. Der Backslash verliert seine Sonderbedeutung nie. Das hätte ich anmerken sollen.

                Liebe Grüße aus Ellwangen,

                Felix Riesterer.

                1. hi,

                  stimmt, hier war ich ungenau. Der Backslash verliert seine Sonderbedeutung nie.

                  Wer Korinthen kacken wollte, würde jetzt anmerken: Ausser, wenn er hinter einem Backslash steht *bg*

                  gruß,
                  wahsaga

                  --
                  /voodoo.css:
                  #GeorgeWBush { position:absolute; bottom:-6ft; }
              2. Seid gegrüßt!

                Du siehst mich fragend? o_O

                --
                Bis Später
                    
                ________________________________________________________________
                [Testversion meiner Seite] [Zwei unterwegs in Australien]
            2. Moin!

              In einer Character Class haben nur noch zwei Zeichen besondere Bedeutung: die schließende eckige Klammer (sie schließt die Character Class wieder) und das Zirkumflex (es negiert die CC).

              4, nicht 2! (Warum fühle ich mich an die spanische Inquisition erinnert?)

              Auf den "" hat wahsaga schon hingewiesen. Du hast aber noch das "-" vergessen: [a-z].

              -- Skeeve

            3. Seid gegrüßt!

              So ich habe jetz
              preg_replace(~                 // Beschr.              Bsp.          Nr.
                 <a href="
                  ([a-zA-Z.]+)              //Buchstaben, Punkt     index.php     1
                  (?:?)                     //das Fragezeichen      ?             2
                  (.+)?                      //irgendwas             text=asd      3
                  "~,

              '$1;$3&amp;' . SID .'">', $tpl_source);
              geht aber immer noch ne!

              Könntest du /ihr mir evtl. noch mal helfen.

              --
              Bis Später
                  
              ________________________________________________________________
              [Testversion meiner Seite] [Zwei unterwegs in Australien]
              1. Moin!

                Seid gegrüßt!

                So ich habe jetz
                preg_replace(~                 // Beschr.              Bsp.          Nr.
                   <a href="
                    ([a-zA-Z.]+)              //Buchstaben, Punkt     index.php     1
                    (?:?)                     //das Fragezeichen      ?             2
                    (.+)?                      //irgendwas             text=asd      3
                    "~,

                '$1;$3&amp;' . SID .'">', $tpl_source);
                geht aber immer noch ne!

                Könntest du /ihr mir evtl. noch mal helfen.

                1. Ist das zu kompliziert, 2. ist Dein "3" in Wahrheit "3" weil Dein "2" nicht gezählt wird (?: ) ist nur zur Gruppierung, nicht fürs Capture.

                preg_replace(
                  ~(<a href="[^"?]+)??~, '$1?'. SID .'&amp;', $tpl_source);

                Sollte es tun. Allerdings kenne ich PHP nicht gut.

                Noch besser ist:
                ~(<a\b[^>]+\bhref="[^"?]+)??~
                Falls da ein onmouseover oder sowas zwischen steht.

                -- Skeeve

                1. Moin!

                  Krrektur: 2. ist Dein "3" in Wahrheit "2" weil Dein "2" nicht gezählt wird (?: ) ist nur zur Gruppierung, nicht fürs Capture.

                  -- Skeeve