PHP HTML parsen - Regular Expression

Lord Alien

Lt. Junior Grade
Registriert
Apr. 2007
Beiträge
258
Hallo Community,

ich bin gerade dabei ein kleines php-script zu schreiben mit dem ich HTML-Code parsen möchte.

Und zwar möchte ich alle Leerzeichen durch "&nbsp;" ersetzen. Da allerdings mein Input bereits HTML-Code enthalten kann, möchte ich natürlich nicht das zB "<span style="..."> zu "<span&nbsp;style="..."> wird.

Meine Wahl ist auf eine Regular Expression gefallen um diese logik zu realisieren. Nachdem ich mir die basics zum Thema Regular Expression angelesen hab und das ganze auch munter mit "grep" unter Linux ausprobiert habe hab ich mir noch ein "Cheatsheet" heruntergeladen um immer schnell etwas nachschauen zu können.

Jetzt entsteht hier leider folgendes Problem:
Ich möchte ja auf das Zeichen "<" bzw. ">" prüfen. Dieses Zeichen steht auf meinem Cheatsheet in der Gruppe Meta-Zeichen. Muss also dementsprechend escaped werden. Escapezeichen ist "\". Soweit so gut. Mein Problem ist jetzt: die Kombination "\>" bzw. "\<" hat auch eine spezielle Bedeutung (laut dem Cheatsheet von addedbytes.com) nämlich "End of word" bzw. "Start of Word"?!?

Stimmt diese Information überhaupt? Wenn ja wie kann ich das ganze umgehen?

Mein erster Ansatz war folgende Regular Expression:
Code:
[\<]{0,}* *[\>]{0,}
Leider gibt das direkt einen Warning vom PHP-Parser: Warning: preg_replace(): Compilation failed: nothing to repeat in offset 8 in /<pfad>/<zur>/<Datei>/ on line <zeilennr.>

Prinzipiell sieht mein php-Code folgendermaßen aus:
PHP:
$patterns = array('/ /', '/#/', '/RR/i')
$replacements = array('&nbsp;', '<span class="grau">#</span>', '<span class="blau">RR</span>')
$ergebnis = preg_replace($patterns, $replacements, $_POST['text'];
echo $ergebnis:
$_POST['text'] ist nur ein kleines textarea das entsprechend per form an mein Script übertragen wird.

Ich hoffe einige Leute kennen sich hier besser mit Regular Expressions aus, als/wie ich :rolleyes:

Bin für jede Hilfe dankbar!

mfg
Alien
:alien_alt:
 
in php regexp brauchst < und > nicht escapen. Jedenfalls wäre mir das nicht bewusst.

ich bezweifel ob es die eleganteste Lösung ist, aber auf die schnelle ist mir nichts besseres eingefallen. Würd mich auch interessieren, wie man dies ohne callback funktion lösen könnte...

PHP:
$s = "adf sfas <span style='font-weight:bold;'>f  <i >a a</i></span> asf<span style='font-weight:bold;'>fett</span> asdfasd sad";
echo $s."<br>\n";

$s = preg_replace_callback('/([^<]*)(<.*?>)(.*?)(<.*?>)/',  create_function('$matches', 'return preg_replace("/\s/", "&nbsp;", $matches[1]).$matches[2].preg_replace("/\s/", "&nbsp;", $matches[3]).$matches[4];'), $s);
$s = preg_replace_callback('/([^>]*)$/',  create_function('$matches', 'return preg_replace("/\s/", "&nbsp;", $matches[1]);'), $s);
echo $s."<br>\n";

aus
PHP:
adf sfas <span style='font-weight:bold;'>f  <i >a a</i></span> asf<span style='font-weight:bold;'>fett</span> asdfasd sad
wird
PHP:
adf&nbsp;sfas&nbsp;<span style='font-weight:bold;'>f&nbsp;&nbsp;<i >a&nbsp;a</i></span>&nbsp;asf<span style='font-weight:bold;'>fett</span>&nbsp;asdfasd&nbsp;sad

wozu brauchst du das eigentlich ?
 
Zuletzt bearbeitet:
Danke für die Antworten.

@fry2k: Die möglichkeit von Mr.Snoot scheint mir wohl die elegantere :)

@Mr. Snoot: Könntest du das evtl. erklären was er da jetzt genau macht? Oder hast du das jetzt auch "nur" mehr oder weniger hier reinkopiert. Funktionieren tut es auf jedenfall einwandfrei, nur verstehen würde ich es auch gerne.
 
Vielleicht hilft dir die Erklärung, die ich schon mal im SelfHTML-Forum bekommen habe; ich verstehs selbst nicht so 100%-ig, besser erklären könnt ichs jedenfalls auch nicht :D (in diesem Fall ersetze ich $s nicht durch $r sondern $s durch <b>$s</b>)
PHP:
»» Vielleicht könnte mir auch jemand erklären, wie der komplette Ausdruck genau arbeitet, denn wirklich durchschauen kann ich ihn nicht:
»» 
»»   // $s case-insensitive in $t hervorheben:
»»   preg_replace("/((<[^>]*)|$s)/ie", '"\2"=="\1"? "\1":"<b>\1</b>"', $t);


Gematcht werden Elemente, die entweder "<" bis ausschließlich ">" sind, und $s, was auch immer darin stehen mag. In der Ersetzung ist eine Abfrage in Kurzform:

[Bedingung] ? [falls wahr] : [andernfalls], die innerhalb der Abfrage umgesetzt wird. durch die doppelte Klammerung der Tags wird ein so gematchtes Tag sowohl in \1 als auch in \2 gespeichert. Wenn also \1 gleich \2 ist, also ein Tag geparst wurde, wird dieses unverändert zurückgegeben, ansonsten wird, wenn \2 leer ist, also kein Tag gematcht wurde, <b>$s</b> zurückgegeben.

Das Ergebnis ist, dass $s in <b>-Tags gesetzt wird, es sei denn, es steht in einem Link. Diese Ersetzung hätte man auch verständlicher und/oder eleganter machen können, aber sicher kaum kürzer oder schneller.

Gruß, LX
 
Zuletzt bearbeitet:
Alles klar, dankeschön.

Wenn ich mir dann noch die Regular Expression komplett klar gemacht hab sollte das hinhauen :D
 
Zurück
Oben