Thomas: RegEx-Problem

Hallo allerseits

Ich habe ein kleines Problem, bei dem ihr mir sicher weiter helfen könnt.
Also, ich habe eine Zeichenkette, bei der ich per while-regex jeweils eine bestimmte Zeichenfolge herauslese und (in meinem richtigen script dynamisch) ersetze. Also "suchen und ersetzen" geht auf keinen Fall.

Hier mein Beispiel (die Zahlen könnten beliebige Zeichen sein):
<code>
$text = "111ab222ab333ab444";
while ($text =~ /(.*?)ab([^ab]*)/)
    {
    $text2 .= $1.'xy'.$2;
    }
</code>
$text2 sollte dann so aussehen: "111xy222xy333xy444". Es dürfen also keine Zeichen verloren gehen, auch die am Schluss nicht. :)

Das Problem ist hier, dass die Stelle [^ab] nach NICHT-"a" oder NICHT-"b" sucht. Wie kann ich nach NICHT-"ab" suchen?
Oder gibts noch ne ganz andere Variante?

  1. Hallo Thomas,

    Beliebig viele Zeichen ohne "ab" bekomst Du mit (?:(?!ab).)*
    (?:) ist eine non-capturing group, d.h. eine Klammerung ohne dass der Wert gespeichert wird.
    (?!) ist eine negative Lookahead-Sequenz, d.h. an dieser stelle wird der reguläre Ausdruck nur weiter angewand, wenn der Ausdruck in den Klammern nicht passt.

    Aber wenn Du einfach nur ab durch xy erstetzen willst, kannst Du ja auch einfach $text =~ s/ab/xy/g;

    Grüße

    Daniel

    1. (?!) ist eine negative Lookahead-Sequenz

      Den hab ich nicht gekannt. Das ist die Lösung, danke!
      (?!) ist in selfhtml leider auch nicht beschrieben, (?:) allerdings schon.

      Aber wenn Du einfach nur ab durch xy erstetzen willst, kannst Du ja auch einfach $text =~ s/ab/xy/g;

      Scherzkeks. :) Das war doch nur ein Beispiel für was hochkomplexes.

      1. Hallo Thomas,

        In Selfhtml stehen nur die Grundlagen zu dem Thema.
        Guck mal in die Perldoku:
        http://www.perldoc.com/perl5.8.0/pod/perlretut.html
        Da gibt es noch einiges mehr als (?!)

        Grüße

        Daniel

  2. Oder gibts noch ne ganz andere Variante?

    $text =~ tr/ab/xy/;

    Struppi.

    1. Hallo Struppi,

      $text =~ tr/ab/xy/;

      Also a durch x und alle b durch y ersetzen, ob er das wirklich will?

      Grüße

      Daniel

      1. $text =~ tr/ab/xy/;
        Also a durch x und alle b durch y ersetzen, ob er das wirklich will?

        Ich hatte es schon mitgelesen, aber aus seiner Fragestellung läßt sich genau das schließen.

        Hier mein Beispiel (die Zahlen könnten beliebige Zeichen sein):
        <code>
        $text = "111ab222ab333ab444";
        while ($text =~ /(.*?)ab([^ab]*)/)
            {
            $text2 .= $1.'xy'.$2;
            }
        </code>
        $text2 sollte dann so aussehen: "111xy222xy333xy444". Es dürfen also keine Zeichen verloren gehen, auch die am Schluss nicht. :)

        #!/usr/bin/perl -w
        use strict;
        my $text = "111ab222ab333ab444";
        my $text2 = $text;
        $text2 =~ tr/ab/xy/;
        print "$text\n$text2";

        führt absolut zu dem von ihm gewünschten Ergebnis.

        Struppi.

        1. Ich hatte es schon mitgelesen, aber aus seiner Fragestellung läßt sich genau das schließen.

          Ja, die Formulierung war nicht ganz einfach. Auf der anderen Seite doch verständlich, weil mir Daniel ja schon geholfen hat.

          Wenn Du wissen willst, wofür ich das brauche, ich mach einen Template-Parser, der für meine Ansprüche genügt und vorallem extrem schnell ist. Den HTML::TEMPLATE-Parser kannst ja nicht gebrauchen. der ist etwa Faktor 30 zu langsam!

          sub fill_tmpl
          {
              my $tmpl_ref = shift;
              my $hash_ref = shift;
              my $tmpl;

          my $vorher;
              my $tmpl_art;
              my $tmpl_name;
              my $tmpl_inhalt;
              my $nachher;

          while ($$tmpl_ref =~ /(.*?)<tmpl_(\w+)[\s]+name="(\w+)">(.+?)</tmpl>((?:(?!<tmpl).)*)/gs)
                  {
                  $vorher      = $1;
                  $tmpl_art    = $2;
                  $tmpl_name   = $3;
                  $tmpl_inhalt = $4;
                  $nachher     = $5;

          $tmpl .= $vorher;
                  if    ($tmpl_art eq 'if')
                      {
                      $tmpl .= $tmpl_inhalt if $$hash_ref{$tmpl_name};
                      }
                  elsif ($tmpl_art eq 'unless')
                      {
                      $tmpl .= $tmpl_inhalt unless $$hash_ref{$tmpl_name};
                      }
                  elsif ($tmpl_art eq 'var')
                      {
                      $tmpl .= $$hash_ref{$tmpl_name};
                      }
                  elsif ($tmpl_art eq 'loop')
                      {
                      # kommt noch :)
                      }
                  $tmpl .= $nachher;
                  }

          $$tmpl_ref = $tmpl;
          }