Problem mit regulären Ausdrücken
Dimitri Rettig
- perl
Hallo,
ich möchte mit Perl prüfen, ob eine Zeichenkette ein HTML-Elemente mit dem Attribut title enthält:
if (/<(?:.* )?title *= *("?).+\1(?: .*)?>/i)
{
print yeah!;
}
Hier mein Gedankengang:
<(?:.* )? Es können beliebig viele Zeichen nach der Klammer kommen, dann muss aber auch das Zeichen vor title ein Leerzeichen sein. title kann auch direkt nach < kommen, das ist mir egal.
title *= * Es können beliebig viele Leerzeichen zwischen title und = bzw. zwischen = und dem Wert des Attributes vorkommen, z. B.
<img title = ...>
("?).+\1 Der Wert des Attributes steht oftmals nicht zwischen Anführungsstrichen. Diese sind also optional ("?). Der Wert des Attributes ist mindestens ein Zeichen lang. Wurden am Anfang Anführungsstriche gesetzt, so müssen sie auch am Ende gesetzt worden sein \1.
(?: .*)?> Es können weitere Angaben folgen. Wenn dies der Fall ist, dann muss aber das Zeichen unmittelbar nach dem title-Attribut ein Leerzeichen sein.
Das Problem ist, dass auch dieser String passt:
<img title="irgendeintitel> Ich denke, dies liegt daran, dass title *= * die Gänsefüßchen " ebenfalls einschließt. Dann findet ("?) keine Anführungsstriche und dementsprechend ist \1 ebenfalls "" (leer). Wie soll ich nun mein Programm abändern, dass es hinhaut?
Mit freundlichen Grüßen
Dimitri Rettig
Hi,
Hier mein Gedankengang:
<(?:.* )? Es können beliebig viele Zeichen nach der Klammer kommen, dann muss aber auch das Zeichen vor title ein Leerzeichen sein. title kann auch direkt nach < kommen, das ist mir egal.
Hier würde ich aber das > ausschließen. Sonst kann der Tag schon wieder aufgehört haben.
Das ist, denke ich auch die Lösung deines Problemes. Schließe einfach die Zeichen die nicht vorkommen sollen aus (mit [^>"] z.B.).
Grüße Andres Freund
Hallo Dimitri,
ich möchte mit Perl prüfen, ob eine Zeichenkette ein HTML-Elemente mit dem
Attribut title enthält:if (/<(?:.* )?title *= *("?).+\1(?: .*)?>/i)
{
print yeah!;
}
Matcht auf:
<> title=blahr>
<title=><blahr>
....
Hier mein Gedankengang:
<(?:.* )? Es können beliebig viele Zeichen nach der Klammer kommen, dann muss
aber auch das Zeichen vor title ein Leerzeichen sein. title kann auch direkt
nach < kommen, das ist mir egal.
Es duerfen aber nicht beliebige Zeichen nach einem kleiner-als kommen. Ausserdem
matcht (?:.* ) auch auf < title. Also sinnvoller:
<(?:[^>]+ )?
title *= * Es können beliebig viele Leerzeichen zwischen title und = bzw.
zwischen = und dem Wert des Attributes vorkommen, z. B.
<img title = ...>
Sinnvoll.
("?).+\1 Der Wert des Attributes steht oftmals nicht zwischen Anführungsstrichen.
Diese sind also optional ("?).
Was ist mit '?
Der Wert des Attributes ist mindestens ein Zeichen lang.
Aber nicht beliebige Zeichen ;) Wenn das Attribut in " steht, duerfen keine " drin
vorkommen. Steht es in ', so duerfen keine ' drin vorkommen. Ist das Attribut
"freistehend", so darf kein Leerzeichen enthalten sein.
Wurden am Anfang Anführungsstriche gesetzt, so müssen sie auch am Ende
gesetzt worden sein \1.
Korrekt.
So kommen wir also zu:
(?:(?:"[^"]+")|(?:'[^']+')|\S+)
(?: .*)?> Es können weitere Angaben folgen. Wenn dies der Fall ist, dann muss
aber das Zeichen unmittelbar nach dem title-Attribut ein Leerzeichen sein.
Ausserdem duerfen keine > drin vorkommen. Also besser:
(?: [^>]+)?
Daraus folgt:
/<(?:[^>]+ )?title *= *(?:(?:"[^"]+")|(?:'[^']+')|\S+)(?: [^>]+)?/
Ich persoenlich wuerde an deiner Stelle allerdings das ganze nicht ausschliesslich auf
RegExen basierent loesen.
Gruesse,
CK
Hallo Christian,
vielen Dank für dein Hilfe. Jetzt sieht das ganze schon besser aus. Nun muss ich das alles noch etwas abändern und an mein Programm anpassen.
Ich persoenlich wuerde an deiner Stelle allerdings das ganze nicht ausschliesslich auf
RegExen basierent loesen.
Was würdest du an meiner Stelle benutzen?
Mit freundlichen Grüßen
Dimitri Rettig
Hallo Dimitri,
Ich persoenlich wuerde an deiner Stelle allerdings das ganze nicht ausschliesslich
auf RegExen basierent loesen.Was würdest du an meiner Stelle benutzen?
HTML::Parser (oder einen beliebigen anderen HTML Parser ;)
Gruesse,
CK
Hallo Christian,
Daraus folgt:
/<(?:[^>]+ )?title *= *(?:(?:"[^"]+")|(?:'[^']+')|\S+)(?: [^>]+)?/
Coole Sache, ich glaube jetzt habe sogar ich kapiert, wie man an solche komplexen RegEx herangeht.
mfg Torsten
Hallo Siechfred,
Coole Sache, ich glaube jetzt habe sogar ich kapiert, wie man an solche komplexen
RegEx herangeht.
Nicht schwer, gelle? Allerdings, wirklich komplex ist er nicht :) Da hab ich schon besseres
gesehen. André Malo hat (hatte?) ein grosses Fable fuer *komplizierte* RegExes. Oder
wenn du mal den RegEx von Jeffrey E. Friedl zur Syntax-Ueberpruefung von E-Mails liest,
der ist auch recht kompliziert ;)
Gruesse,
CK
Oh, jetzt ist mir ein Fehler aufgefallen, aber erst einmal der Code (etwas verändert, auf Grund des Postings von Andreas Freund weiter unten).
#!/usr/bin/perl
while (<>)
{
if (/<(?:[^>]* )?title *= *("?).+\1(?: .*)?>/i)
{
print "+++ $& +++\n";
}
}
Das Problem ist, dass auch dieser String passt:
<img title="irgendeintitel> Ich denke, dies liegt daran, dass title *= * die Gänsefüßchen " ebenfalls einschließt.
Habe vergessen, dass die regulären Ausdrücke von Perl nicht ganz die gleichen sind wie von der bash. Selbstverständlich schließt *= * die G#nsefüßchen _nicht_ ein. Jetzt weiß ich aber auch nicht, wo der Fehler liegen könnte.
Mit freundlichen Grüßen
Dimitri Rettig