regulärer Ausdruck tut nicht wie ich möchte...
Hilker
- perl
0 Felix Riesterer0 MudGuard0 seth0 *Markus
Wie schon dem Titel zu entnehmen plage ich mich mit einem regülären Ausdruck herum, komme aber irgendwie nicht dahinter, wo mein Denkfehler liegt.
Ich hab hier mal aufgemalt. worum es geht, und wie ich es verstehe:
$text =~ s/(<[^>|"]+>)*"/&/g;
| | | ||| | |
Beginnt mit < ----+ | | ||| | |
Gefolg von nicht > ------+ | ||| | |
oder --------+ ||| | |
von " ----------+|| | |
möglichst oft -----------+| | |
bis > ------------+ | |
Suchmuster " ---------------+ |
ersetzen durch & ------------------+
Folgender Code ausgeführt
$text = qq{<span style="color: blue;">Hier ist ein "Test-text" mit Anführungszeichen</span>};
$text =~ s/(<[^>|"]+>)*"/&/g;
print "Content-Type: text/html\n\n";
print $text;
Ergibt aber:
<span style=&color: blue;&>Hier ist ein &Test-text& mit Anführungszeichen</span>
Und die """ im span Tag möchte ich natürlich NICHT ersetzen, sondern nur diejenigen, die NICHT innnerhalb von TAGs sind.
Wer kann mir den entscheidenden Hinweis geben?
mfG der Hilker
Lieber Hilker,
$text =~ s/(<[^>|"]+>)*"/&/g;
was soll die Pipe "|" im Suchmuster? Eine character class funktioniert schon wie ein "oder". [^>"]+ findet alles, was aus Zeichen besteht, die weder > noch " sind. Wenn in Deinen Strings keine Pipe vorkommt, dann sollte sie in Deinem Suchmuster keine Probleme bereiten, ist aber vom Verständnis her vollkommen falsch dort.
<span style=&color: blue;&>Hier ist ein &Test-text& mit Anführungszeichen</span>
Und die """ im span Tag möchte ich natürlich NICHT ersetzen, sondern nur diejenigen, die NICHT innnerhalb von TAGs sind.
Ich verstehe nichts von der Syntax in Perl und seinen Funktionen, aber kann es sein, dass die Code-Zeile | $text =~ s/(<[^>|"]+>)*"/&/g;
unvollständig ist, da sie den Ausdruck in Klammern nicht unverändert in den String zurückschreibt (Backreference)?
In PHP sähe das bei mir so aus:
$text = preg_replace('/(<[^>"]+>)*"/', "$1&", $text);
Das $1 ist die Backreference, die den Treffer des Ausdrucks in der Klammer repräsentiert (und dort wieder einfügt), während alles andere ersetzt wird.
Liebe Grüße aus Ellwangen,
Felix Riesterer.
Lieber Hilker,
$text =~ s/(<[^>|"]+>)*"/&/g;
was soll die Pipe "|" im Suchmuster? Eine character class funktioniert schon wie ein "oder". [^>"]+ findet alles, was aus Zeichen besteht, die weder > noch " sind. Wenn in Deinen Strings keine Pipe vorkommt, dann sollte sie in Deinem Suchmuster keine Probleme bereiten, ist aber vom Verständnis her vollkommen falsch dort.
Ja, dacht ich auch /(<[^>"]+>)/ findet aber zwar </span> aber NICHT <span style="color: blue;">, obwohl es das nach meinem Verständnis tun müßte!
»»...unvollständig ist, da sie den Ausdruck in Klammern nicht unverändert in den String zurückschreibt (Backreference)?
Ich ändere nun schon solange daran rum dass ich Knoten im Kopf hab :)
In PHP sähe das bei mir so aus:
$text = preg_replace('/(<[^>"]+>)*"/', "$1&", $text);
Das $1 ist die Backreference, die den Treffer des Ausdrucks in der Klammer repräsentiert (und dort wieder einfügt), während alles andere ersetzt wird.
ja klar... ist in Perl genauso... PHP ist ja eh "nur" nen ableger von Perl :))))
Liebe Grüße aus Ellwangen,
Felix Riesterer.
Danke! aber wie gesagt, hat es nicht wirkich geholfen!
Gruß, der Hilker
Nabend Hilker,
ja klar... ist in Perl genauso... PHP ist ja eh "nur" nen ableger von Perl :))))
nur historisch betrachten. Konzeptionell sind dies zwei Paar Schuhe.
Gruß aus Berlin!
eddi
Nabend Hilker,
Tach Xarax,
nur historisch betrachten. Konzeptionell sind dies zwei Paar Schuhe.
Ja sicher, darum ja auch ":))))"
Gruß aus Berlin!
eddi
Gruß, der Hilker
Hi,
Ja, dacht ich auch /(<[^>"]+>)/ findet aber zwar </span> aber NICHT <span style="color: blue;">, obwohl es das nach meinem Verständnis tun müßte!
Nein den die " verneinst Du ja ebenso.
<
gefolgt von
nicht >
nicht "
ein oder mehrere
Gruesse, Joachim
Hi,
Tach Joachim!
Nein den die " verneinst Du ja ebenso.
<
gefolgt von
nicht >
nicht "
ein oder mehrere
OK, soweit bin ich jetzt auch schon, nun sieht mein Ergebnis wie folgt aus:
$text =~ s/(<([^>]|["])+>(?:.*?))"/$1&/g;
Das ersetzt allerdings nur das Erste vorkommende ´"´ zwischen <tag> und </tag>
*grrrmpf* Mist!
Gruesse, Joachim
der Hilker
Hi,
*grrrmpf* Mist!
schau mal:
<?php
$text = 'Hier ist ein "Test-text" mit Anführungszeichen<span style="color: blue;">Hier ist ein "Test-text" mit Anführungszeichen</span> test <span style="color: blue;">Hier ist ein "Test-text" mit Anführungszeichen</span> test = "lala" textex';
function set_entitie($match) {
return $match[1] . preg_replace("/((\134\134)?\042)/i", "xxxx", $match[2]);
}
$text = preg_replace_callback(
"#(</?[^>]+>)?([^<]+)#i",
"set_entitie",
$text
);
echo htmlentities($text);
?>
Hab den text extra verlängert, damits fuer mehrere Situationen passt. Das mit dem Callback-Konstrukt habe ich von *lulu* gelernt.
Gruesse, Joachim
Lieber Hilker,
Anscheinend darf man hier nicht besonders gierig vorgehen. Folgendes Beispiel in Javascript erfüllt seinen Zweck:
var text = 'Lorem "ipsum dolor" sit <span class="merksatz"> amet, "consectetuer adipiscing elit"</span>, <span class="normal" id="test">sed diam nonummy</span> nibh euismod tincidunt...';
text = text.replace(/((?:(?!<)[^"])*)"(<[^>]+>)?/m, "$1"$2");
alert(text);
Liebe Grüße aus Ellwangen,
Felix Riesterer.
Hi,
s/(<[^>|"]+>)*"/&/g;
( bis ) gruppiert mit Speichern
* von dem vorherigen Teil (hier: der Gruppe) beliebig viele (auch 0)
Danach ein "
Da der gesamte Teil vor dem " optional ist (kann ja auch 0 mal vorkommen), wird jedes " durch & ersetzt.
Warum eigentlich?
Bei Ersetzung durch " wär's mir schon schleierhaft (für korrektes HTML ist es nicht notwendig, " außerhalb von "-begrenzten Attributwerten zu ersetzen).
Aber warum Du Anführungszeichen durch Kaufmannsund ersetzen willst, erschließt sich mir überhaupt nicht.
Desweiteren: Der Teil in der () hat andere Bedeutung als Du vermutest:
< und > matchen genau diese Zeichen.
Dazwischen hast Du eine negierte Zeichenklasse - die matcht auf ein beliebiges Zeichen außer den genannten "größer", "Pipe" und "Anführungszeichen".
Davon soll es mindestens eins geben.
Innerhalb einer Zeichenklasse haben die meisten Metacharacters keine Meta-Bedeutung mehr.
cu,
Andreas
Hi,
Moin!
Bei Ersetzung durch " wär's mir schon schleierhaft (für korrektes HTML ist es nicht notwendig, " außerhalb von "-begrenzten Attributwerten zu ersetzen).
Aber warum Du Anführungszeichen durch Kaufmannsund ersetzen willst, erschließt sich mir überhaupt nicht.
Ich möchte natürlich " durch &qout; ersetzen, habe nur & gewählt, damit ich nich ständig im quelltext schauen muß, ob das nun " oder " ist, da der browser es ja wieder rückwandelt.
Desweiteren: Der Teil in der () hat andere Bedeutung als Du vermutest:
< und > matchen genau diese Zeichen.
Dazwischen hast Du eine negierte Zeichenklasse - die matcht auf ein beliebiges Zeichen außer den genannten "größer", "Pipe" und "Anführungszeichen".
Davon soll es mindestens eins geben.Innerhalb einer Zeichenklasse haben die meisten Metacharacters keine Meta-Bedeutung mehr.
OK, das mit den Zeichenketten und der negation hab ich inziwschen verstanden und den code dementsprechend geändert, sodaß ich zu einer funktionierenden lösung mit /eg komme in der ich den text zwischen den >< in einem weiteren regexp ersetzen lasse und zurückgebe.
Das ist sicher nicht optimal, und bin weiterhin auf der Suche nach einer "einzeilen-lösung"
cu,
Andreas
Gruß, der Hilker
Lieber Hilker,
... sodaß ich zu einer funktionierenden lösung mit /eg komme in der ich den text zwischen den >< in einem weiteren regexp ersetzen lasse und zurückgebe.
Das ist sicher nicht optimal, und bin weiterhin auf der Suche nach einer "einzeilen-lösung"
was hat Dir an meiner Javascript-Lösung nicht geschmeckt?
Liebe Grüße aus Ellwangen,
Felix Riesterer.
gudn tach!
Und die """ im span Tag möchte ich natürlich NICHT ersetzen, sondern nur diejenigen, die NICHT innnerhalb von TAGs sind.
Wer kann mir den entscheidenden Hinweis geben?
eine moeglichkeit waere, den php-code von php faq zu "uebersetzen".
eine andere moeglichkeit waere, den string zeichenweise abzuklappern, einen zaehler, den man vorher auf null gesetzt hat, fuer jedes vorkommnis von "<" um eins zu erhoehen und fuer jedes ">" um eins zu dekrementieren und jedes mal, wenn der zaehler auf 0 ist und man ein " gefunden hat, dieses ersetzt.
nachteile sind klar: falls z.b. javascript-code mit sowas wie "if(i>j)" auftaucht, ist alles im eimer. kann man aber auch verhindern.
prost
seth
Hallo,
ich weiß zwar nicht genau was du vor hast, aber würde es vielleicht mit HTML::Entities funktionieren?
Markus.