Jörg: Regular Expressions: Elegantere Lösung möglich?

Hi, ich hab folgendes Problem:
In mehreren längeren Textdokumenten tauchen Namen auf, die
ersetzt werden sollen. Aber nur dann, wenn sie innerhalb des tags
<p class="txt4"> ... </p>
auftauchen.
Ansonsten sollen die Namen unverändert bleiben.
Innerhalb des tags <p class="txt4"> ... </p> können die Namen
keinmal, einmal oder auch mehrmals stehen.

Die einfache Ersetzungsfunktion
$text =~ s/$suchb/$ersatz/g;
geht nicht, weil $suchb in $text nur innerhalb der Zeichenkette
<p class="txt4">.*?</p>
ausgetauscht werden soll.

Bislang behelfe ich mich mit einer while-Schleife. Das funktioniert auch, aber es erscheint mir wenig elegant und auch zeitaufwändig:

while ($text =~ /<p class="txt4">.*?$suchbegriff.*?</p>/) {
 $text =~ /<p class="txt4">(.*?)</p>/;
 my $korr = $1;
 $korr =~ s/$suchb/$ersatz/g;
 $text =~ s/<p class="txt4">.*?$suchb.*?</p>/<p class="txt4">$korr</p>/;
}

Gibt es eine elegantere Lösung?

  1. 你好 Jörg,

    Bislang behelfe ich mich mit einer while-Schleife. Das funktioniert auch,
    aber es erscheint mir wenig elegant und auch zeitaufwändig:

    while ($text =~ /<p class="txt4">.*?$suchbegriff.*?</p>/) {
    $text =~ /<p class="txt4">(.*?)</p>/;
    my $korr = $1;
    $korr =~ s/$suchb/$ersatz/g;
    $text =~ s/<p class="txt4">.*?$suchb.*?</p>/<p class="txt4">$korr</p>/;
    }

    Ich verstehe nicht so recht, was gegen

    s!<p class="txt4">(.*?)$suchb(.*?)</p>!<p class="txt4">$1$korr$2</p>!g;

    spricht. Test-Version:

      
    #!/usr/bin/perl -w  
      
    use strict;  
      
    my $text = '<p class="h4">Dies ist ein Test</p> Dies ist ein Test <p>Dies ist ein Test <p class="h4">Dies ist ein Test</p> Dies ist ein Test</p>';  
    $text =~ s!<p class="h4">(.*?)Dies(.*?)</p>!<p class="h4">$1Das$2</p>!g;  
      
    print $text,"\n";  
    
    

    再见,
     克里斯蒂安

    --
    Wenn gewöhnliche Menschen Wissen erlangen, sind sie weise. Wenn Weise Einsicht erlangen, sind sie gewöhlnliche Menschen.
    http://wwwtech.de/
    1. Hi Christian,

      $text =~ s!<p class="h4">(.*?)Dies(.*?)</p>!<p class="h4">$1Das$2</p>!g;

      funktioniert nicht, weil "Dies" (Dein Beispiel) bisweilen mehrfach auftaucht. (Hatte ich in meiner Frage auch geschrieben). Deine Programm-Zeile ersetzt nur das 1.Vorkommen:

      #!/usr/bin/perl -w
      use strict;
      my $text = '<p class="h4">Dies ist ein Test. Dies ist ein Test.</p>';
      $text =~ s!<p class="h4">(.*?)Dies(.*?)</p>!<p class="h4">$1Das$2</p>!g;
      print $text,"\n";

      Ergebnis:
      <p class="h4">Das ist ein Test. Dies ist ein Test.</p>

      Daher meine (ich vermute: unelegante) while-Schleife.
      Jörg

  2. Hi,

    Gibt es eine elegantere Lösung?

    man kann reguläre Ausdrücke auch verschachteln, z.B. so:

    $text=~s/<p class="txt4">(.*?$suchb.*?)</p>/my $korr=$1;$korr=~s#$suchb#$ersatz#g;'<p class="txt4">'.$korr.'</p>'/eg;

    Eingesetzt wird das, was hinten rauskommt. Im Prinzip ist das auch nicht anders als deine Schleife, nur kürzer. Mit Look-Aheads und Look-Behinds kommt man hier glaube ich nicht weiter, weil dabei keine Zeichenketten von variabler Länge erlaubt sind.