?R Rekursion

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

  • ?R Rekursion

    Hallo,

    unter Brainstorming habe ich eine Diskussion zum Thema Templates verfolgt. Dort wurde für verschachtelte Blöcke/Schleifen "?R" im Zusammenhang mit RegEx empfohlen. Das Tut und die Seite im Manual dazu habe ich mir bereits reingezogen, allerdings habe ich noch Schwierigkeiten.

    Folgendes Beispiel:
    PHP-Code:
    <?php
    //RegEx:Test
        
    $test="(ab(cd)ef)";
        
    $pattern="%\((((?>[^()]+)|(?R))*)\)%";
        
    preg_match_all($pattern,$test,$matches,PREG_SET_ORDER);
        echo 
    "<pre>\n";
        
    print_r($matches);
        echo 
    "</pre>\n";
    ?>
    liefert mir
    PHP-Code:
    Array
    (
        [
    0] => Array
            (
                [
    0] => (ab(cd)ef)
                [
    1] => ab(cd)ef
                
    [2] => ef
            
    )


    Ich hätte allerdings gerne "cd" als letzten Treffer - also die innerste Ebene.

    Den pattern habe ich wie folgt analysiert:suche eine beliebige Zeichenfolge ohne runde Klammern [^()]+ oder eine Zeichenfolge auf die der Pattern zutrifft innerhalb von ( bzw. ) das sind die \( bzw \). Daher hätte ich als Ergebnis cd erwartet ...

    Nur ?> verstehe ich nicht

    Kann mir jemand helfen das zu kapieren? Vielen Dank!

  • #2
    du mußt das innere erneut 'parsen' ... die rekursion findet nur die passenden teile, ...
    Die Zeit hat ihre Kinder längst gefressen

    Kommentar


    • #3
      achso! Jetzt wird mir das ganze etwas klarer. Dann jage ich mein Ergebnis solange durch eine Schleife bis preg_match keinen Treffer mehr ergibt und habe so die innerste Ebene gefunden - korrekt ?!

      Kommentar


      • #4
        @derHund: habe jetzt eine Schleife drumherum gebaut und bekomme nun endlich die innerste Ebene:
        Code:
        <?php
        //RegEx:Test
        	$test="(ab(cd(ef)gh)ij)";
            $pattern="%\((((?>[^()]+)|(?R))*)\)%";
            do{
            	preg_match($pattern,$test,$match);
                $test=$match[1];
            } while ($match[1]!=$match[2]);
            echo $test;
        ?>
        Und jetzt die große Preisfrage: wie kann ich als Trenner statt der runden Klammer eine Zeichenfolgen definieren (z.B. "<!--" für "(" und "-->" für ")")? Geht das überhaupt?

        Kommentar


        • #5
          Und jetzt die große Preisfrage: wie kann ich als Trenner statt der runden Klammer eine Zeichenfolgen definieren (z.B. "<!--" für "(" und "-->" für ")")? Geht das überhaupt?
          ja, natürlich geht das ... schau mal in dein codeschnipseln, dort habe ich mal exemplarisch etwas veröffentlicht ... bbcode recursiv heißts ... aber warte noch 3min, ich muß den beitrag nochmal updaten ...

          oder poste einen besipel-text, dann bastel ich fix was ...
          Die Zeit hat ihre Kinder längst gefressen

          Kommentar


          • #6
            @derHund: Danke, dein Code-Schnipsel hat mir schon weiter geholfen. Habs jetzt soweit funktionsfähig. Kannst du noch mal drüber schauen ob das so ok ist oder ob es nur zufällig klappt.

            Vermutlich kann ich auch noch das eine oder andere verbessern?

            Code:
            <?php
            //Blöcke im Template rekursiv parsen
            	$test="<!--Begin ab-->123<!--Begin cd-->456<!--End cd-->789<!--End ab-->";
                echo htmlspecialchars($test)."<hr />\n";
                $pattern='%\<\!--Begin ([a-z]+)--\>(((?>[^\<\!--Begin]+)|(?R))*)\<\!--End \1--\>%';
                do{
                	preg_match($pattern,$test,$match);
                    $test=$match[2];
                } while ($match[2]!=$match[3]);
                echo $test;
            ?>
            Vielen Dank für deine Hilfe!

            Kommentar


            • #7
              kleiner Nachtrag:

              habe ein wenig ausprobiert und festgestellt, dass es so nicht funktioniert. Wenn in meinem Beispiel zwischen 456 HTML-Code steht, wird dieser wegen der negierten spitzen Klammer nicht gefunden.

              Ich dürfte also zum negieren nicht
              Code:
              [^\<\!--Begin]+
              benutzen, da es sich um eine Zeichenklasse handelt. Ich müsste es so ausdrücken, das die Zeichenfolge als zusammenhängender String erkannt wird.

              Wenn ich aber nur die eckigen Klammern weglasse wird gar nichts gefunden.

              Wer kann mir hier noch mal auf die Sprünge helfen?

              Kommentar


              • #8
                poste doch mal einen möglichst umfangreicheren beispieltext, und sag, was du finden möchtest, dann geht das bestimmt auch ...
                Die Zeit hat ihre Kinder längst gefressen

                Kommentar


                • #9
                  ok, das ganze soll in meine Template-Klasse. Bisher kann ich einfache Variable tauschen und Blöcke ohne Verschachtelung ersetzen. Nun möchte ich auch Verschachtelungen integrieren. Hier meine Vorlage:
                  PHP-Code:
                  <!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
                  <
                  html>
                  <
                  head>
                  <
                  title>Vorlage mit verschachtelten Blöcken</title>
                  <
                  meta name="author" content="Patrick">
                  <
                  meta name="generator" content="Ulli Meybohms HTML EDITOR">
                  </
                  head>
                  <
                  body>
                  <
                  table border="1">
                      <!--
                  Begin zeile-->
                      <
                  tr>
                          <
                  td>Zeile Nr.:{lfd}</td>
                          <
                  td>
                              <
                  select name="drp1" size="1">
                                  <!--
                  Begin option-->
                                  <
                  option value="{value}">{option}</option>
                                  <!--
                  End option-->
                              </
                  select>
                          </
                  td>
                      </
                  tr>
                      <!--
                  End zeile-->
                  </
                  table>
                  </
                  body>
                  </
                  html
                  und hier die Template-Funktion für Verschachtelungen:
                  Code:
                  <?php
                  	$filename='./vorlage.tpl';
                      $handle = fopen ($filename, "r");
                      $template = fread ($handle, filesize ($filename));
                      fclose ($handle);
                      $pattern='%\<\!--Begin ([a-z]+)--\>(((?>[^()])|(?R)).*)\<\!--End \1--\>%isU';
                      $test=$template;
                      echo $test."<hr />\n";
                      preg_match($pattern,$test,$match);
                      print_r($match);
                      echo "<hr />\n";
                      foreach($match as $value)
                      	echo htmlspecialchars($value)."<br />\n";
                  
                      do{
                      	preg_match($pattern,$test,$match);
                          $test=$match[2];
                      } while ($match[2]!=$match[3]);
                      echo $test;
                      $pattern_var='%{[a-z]+)}%';
                      preg_match_all($pattern_var,$test,$matches,PREG_SET_ORDER);
                      echo "<pre>\n";
                      print_r($matches);
                      echo "</pre>\n";
                  ?>
                  Der obige Code (mit "(ab(cd...") findet die innerste Ebene - dieser scheitern wie beschrieben an der negierten Zeichenklasse. Mit "...?>[^\<\!--Begin]+..." werden ja automatisch alle Tags ausgeschlossen. Eigentlich möchte ich ja nur alles außschließen wo "<!--Begin ([a-z]+)-->.*<!--End \1-->" drin vorkommt.

                  Für dieses Beispiel soll der Block "option" gefunden werden.

                  Kommentar


                  • #10
                    hmm,

                    ehrlich gesagt, verstehe ich dein problem nicht so ganz ...
                    Nun möchte ich auch Verschachtelungen integrieren.
                    da du im end-tag noch einmal den namen des tags angibst, brauchst du nicht einmal ?R verwenden ...
                    Eigentlich möchte ich ja nur alles außschließen wo "<!--Begin ([a-z]+)-->.*<!--End \1-->" drin vorkommt.
                    wozu?
                    Für dieses Beispiel soll der Block "option" gefunden werden.
                    dann kannst du das im pattern doch angeben, ohne die rekursion ... ?

                    wie gesagt, so richtig versteh ich nicht, wo das problem liegt ...
                    Die Zeit hat ihre Kinder längst gefressen

                    Kommentar


                    • #11
                      @derHund: das Problem liegt wie folgt: ich möchte den innersten Block finden - in meinem Beispiel den "option"-Block. In meinem Beispiel weiß ich natürlich wie der innerste Block heißt und kann ihn daher direkt ansprechen. In der täglichen Verwendung kann der innerste Block ja einen beliebigen Namen haben. Dann möchte ich halt den ersten Block finden, in dem kein weiterer Block mehr vorhanden ist. Das erreiche ich, indem ich "<!--Begin [a-z]-->.*<!--End \1-->" ausschließe.

                      In dem Thread unter Brainstorming wurde dafür ?R vorgeschlagen. Ich könnte natürlich auch alles zwischen den o.g. Begin- und End-Marken ausschneiden und das Ergebnis wieder durch preg_match jagen bis er nichts mehr findet ->innerster Block.

                      Ich werde es so mal probieren.

                      Das Prinziep habe ich mit ?R mit meinem vierten Post ja schon realisiert. Nur geht es wie gesagt nicht mit HTML-Tags.

                      Statt <!--Begin ... als Zeichenklasse auszuschließen müsste ich das gesamt Konstrukt ausschließen. Kannst du mir dazu noch einen Tipp geben?

                      Danke.

                      Kommentar

                      Lädt...
                      X