David: reguläre Ausdrücke

Servus,

nachfolgender regulärer Ausddruck dient der Suche nach Tags wie sie in Foren vorkommen, z.B. [quote], [quote:af259def2], [quote:af259def2="username"]:

$searchstring = '/'.
'([[]'.$tagname.')'.  //  1 Start of Start-Tag
'((([:|=])([a-fA-F0-9]*))?)'. //  2 Optional: assignment sign, 3 Optional: Hex-Value
'((([:|=])(.|\n$)*)?)'. //  4 Optional: 2nd assignment,  5 Optional: any value
'([]])'.   //  6 End of Start-Tag
'((.|\n)+?)'.   //  7 Content
'([[][/]'.$tagname.')'. //  8 Start of End-Tag
'([:=]?)'.   //  9 Optional: assignment sign
'([a-fA-F0-9]*?)'.  // 10 Optional: Hex-Value
'([:=]?)'.   // 11 Optional: 2nd assignment
'((.|\n$)*?)'.   // 12 Optional: any value
'([]])'.   // 13 End of End-Tag
'/';

Wenn ich jetzt den ausdruck verwende wird mir der Username  jedoch vom Abschnitt 5 /...(.|\n$)*)?).../ gemeinsam mit Gleichheitszeichen und Anführungszeichen ausgegeben: ="username" statt username
Ich möchte gerne den usernamen ohne Anführungszeichen extrahieren und das Gleichheitszeichen durch 4 rausfiltern.

Falls der umliegende Code zum testen gewünscht ist, kann ich den auch gerne noch posten.

Vielen Dank
David

  1. gudn tach!

    nachfolgender regulärer Ausddruck dient der Suche nach Tags wie sie in Foren vorkommen, z.B. [quote], [quote:af259def2], [quote:af259def2="username"]: [...]

    der code wuerde schon versagen, wenn zwei tags vorkommen, also z.b. bei
      '1[tag:a:x]foo[/tag:a:x]2[tag:b:y]bar[/tag:b:y]'
    denn (.|\n$)* matcht z.b. auch square brackets.

    ein paar anmerkungen zur vereinfachung:
      [[]    ist dasselbe wie [
      []]    ist dasselbe wie ]
      [:|=] ist dasselbe wie [:|=]

    in ([) bzw. (]) sind die runden klammern eigentlich ueberfluessig.

    in ausdruecken wie
      (((foo)(bar*))?)
    wuerde ich nicht backreferences fuer jeden term erstellen. mit ?: kann man gruppieren ohne backreferences zu erstellen.
    z.b.
      (?:(?:(foo)(bar*))?)

    Wenn ich jetzt den ausdruck verwende wird mir der Username  jedoch vom Abschnitt 5 /...(.|\n$)*)?).../ gemeinsam mit Gleichheitszeichen und Anführungszeichen ausgegeben: ="username" statt username
    Ich möchte gerne den usernamen ohne Anführungszeichen extrahieren und das Gleichheitszeichen durch 4 rausfiltern.

    gib mal 'nen beispielstring an.

    prost
    seth

    1. hallo seth,

      jetz habe ich es folgendermaßen gemacht:

      $searchstring = '/'.
       '([[]'.$tagname.')'.
       '((?:([:|=])([a-fA-F0-9]*))?)'.
       '((?:([:|=])(")?((.|\n$)*?)(")?)?)'.
       '(?:[]])'.
       '((.|\n)+?)'.
       '(?:[[][/]'.$tagname.')'.
       '((?:([:|=])([a-fA-F0-9]*))?)'.
       '((?:([:|=])(")?((.|\n$)*?)(")?)?)'.
       '(?:[]])'.
      '/';

      Dadurch erhalte ich den Benutzernamen ohne Anführungszeichen.

      Den Array mit den  Ergebnissen füge ich mal an:

      $pattern_array[0][0]=[quote:c63e8e1118="username"]BLA BLA BLA Inhalt des Elements
      [/quote:c63e8e1118]
      ----------
      $pattern_array[1][0]=[quote
      ----------
      $pattern_array[2][0]=:c63e8e1118
      ----------
      $pattern_array[3][0]=:
      ----------
      $pattern_array[4][0]=c63e8e1118
      ----------
      $pattern_array[5][0]=="username"
      ----------
      $pattern_array[6][0]==
      ----------
      $pattern_array[7][0]="
      ----------
      $pattern_array[8][0]=username
      ----------
      $pattern_array[9][0]=s
      ----------
      $pattern_array[11][0]=BLA BLA BLA Inhalt des Elements
      ----------
      $pattern_array[12][0]=
      ----------
      $pattern_array[13][0]=8
      ----------

      Dort kann man sehen, daß die Begrenzung mit ?: nicht überall was bringt, aber das Ergebnis ist schon etwas knapper als ohne.
      Weshalb die letzen Zeichen von Unterausdrücken in dem Array noch einmal gesondert auftauchen (8 und s) ist mir etwas fremd - ist das normal?

      Momentan wird der Tag in der Variablen $tagname übergeben, sicherlich wäre es jetzt noch möglich, diesen auch per regulärem Ausdruck auszulesen, allerdings habe ich das ganze bereits in einer Schleife integriert und müßte recht viel umschreiben. deswegen lasse ich es jetzt so. Den Performance-Verlust durch mehrmaliges durchlaufen kann ich zur Zeit hinnehmen.
      Das schöne ist, daß der Ausdruck für alle mir bekannten Foren-Tags passt und ich durch den Einsatz bereits jede Menge Code einspare (also Löschen kann).

      Sicherlich kann man da noch etwas kürzen, ich könnte evtl. einige Klamern noch eliminieren, aber das wäre weitgehend nur optischer Natur.

      Viele Grüße
      David

      PS. in meinem ersten Beitrag hatte ich vergessen zu schreiben, daß die Anführungszeichen nicht als Zeichen sondern als entitie im Quelltext auftauchen (&quote;)

      1. gudn tach!

        $searchstring = '/'.
        '([[]'.$tagname.')'.
        '((?:([:|=])([a-fA-F0-9]*))?)'.
        '((?:([:|=])(")?((.|\n$)*?)(")?)?)'.
        '(?:[]])'.
        '((.|\n)+?)'.
        '(?:[[][/]'.$tagname.')'.
        '((?:([:|=])([a-fA-F0-9]*))?)'.
        '((?:([:|=])(")?((.|\n$)*?)(")?)?)'.
        '(?:[]])'.
        '/';

        kuerzer wird's mit den von mir genannten schreibweisen:
         $searchstring = '/'.
          '(['.$tagname.')'.
          '((?:([:|=])([a-fA-F0-9]*))?)'.
          '((?:([:|=])(")?((.|\n$)*?)(")?)?)'.
          ']'.
          '((.|\n)+?)'.
          '[/'.$tagname.
          '((?:([:|=])([a-fA-F0-9]*))?)'.
          '((?:([:|=])(")?((.|\n$)*?)(")?)?)'.
          ']'.
         '/';

        das problem der mehreren tags hintereinander besteht aber immer noch.

        Den Array mit den  Ergebnissen füge ich mal an:

        dafuer gibt's print_r. ;-)

        $pattern_array[9][0]=s
        $pattern_array[13][0]=8

        Dort kann man sehen, daß die Begrenzung mit ?: nicht überall was bringt, aber das Ergebnis ist schon etwas knapper als ohne.

        naja, du musst es halt auch richtig verwenden.
        da du abe noch nicht gesagt hast welche infos du alle extrahieren willst, koennen wir dir auch nur schlecht helfen.

        wenn du nur den username und den content extrahieren willst, dann ginge das in etwa so:

        $searchstring = '/'.
          '['.$tagname.
          '(?:[:|=][a-fA-F0-9]*)?'.
          '(?::|=?(.*?)(?:")?)?'.
          ']'.
          '(.+?)'.
          '[/'.$tagname.
          '(?:[:|=][a-fA-F0-9]*)?'.
          '(?::|=?(.*?)(?:")?)?'.
          ']'.
         '/s';

        beachte den s-modifier.

        und das liesse sich noch mal kuerzen:

        $tag_pattern = $tagname.
          '(?:[:|=][a-fA-F0-9]*)?'.
          '(?::|=?(.*?)(?:")?)?'.
          ']';
         $searchstring = '/'.
          '['.$tag_pattern.
          '(.+?)'.
          '[/'.$tag_pattern.
         '/s';

        Weshalb die letzen Zeichen von Unterausdrücken in dem Array noch einmal gesondert auftauchen (8 und s) ist mir etwas fremd - ist das normal?

        wenn du sowas machst

        /f(.*)r/

        und das z.b. auf den string "foobar" loslaesst, dann wird der string gematcht, und es gilt $1 =="ooba".

        wenn du aber (wie in deinem fall)

        /f(.)*r/

        verwendest, dann wird nur der letzte gematchte ausdruck gespeichert, also $1 == "a".

        Momentan wird der Tag in der Variablen $tagname übergeben, sicherlich wäre es jetzt noch möglich, diesen auch per regulärem Ausdruck auszulesen, allerdings habe ich das ganze bereits in einer Schleife integriert und müßte recht viel umschreiben.

        wahrscheinlich muesstest du das nicht.
        du koenntest einfach
           $tagname = (?:tagX|tagY|tagZ)
        setzen. der regexp-code bliebe derselbe.

        prost
        seth