Regular Expressions: Elegantere Lösung möglich?
Jörg
- perl
0 Christian Kruse0 Jörg
0 Christoph
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?
你好 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";
再见,
克里斯蒂安
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
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.