MoiN, Christian!
Ich habe mal mich hingesetzt und einen RegEx zusammengestellt, der
IMHO in ungefaehr das liefert, was man in der Praxis so benoetigt:
$text = preg_replace('!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?([A-Za-z0-9-]+.)*([A-Za-z0-9-]{3,}.)([a-zA-Z0-9-]+.)*([a-z]{2,})(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!','<a href="$1$2$3$4$5$6$7$8">$1$2$3$4$5$6$7$8</a>',$text);
Ziemlich lang, das Teil. Und leider erkennt es nicht, wenn man eine IP-Adresse eingibt, weil du fest auf das Vorhandensein von zwei oder mehr Buchstaben als TLD prüfst.
Naja, ich kommentiere mal...
^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?
Hier wird nach einem Protokoll gesucht. Ich habe einfach mal FTP,
HTTP und Emails definiert. Wenn es eine EMail ist, wird nach dem
Usernamen geschaut.
Fein. Eventuell haut dir der mailto-Teil ab, weil Usernamen eben durchaus aus mehr als nur Zeichen, Zahlen, Punkt, Unterstrich und Minus bestehen können. Irgendwie gibts auch die Variante, den Usernamen in Anführungsstrichen mit beliebigen Zeichen (auch Leerzeichen) anzugeben.
([A-Za-z0-9-]+.)*
Hier wird nach dem ersten Teil der Domain geschaut. Der darf *nur*
aus den Zeichen A-Za-z0-9 und einem Punkt bestehen und muss
wenigstens ein Zeichen lang sein. Er *muss* aber nicht matchen
(dafuer steht das * am Ende), es kann auch sein, dass wir direkt
zu der Domain kommen (z. B. http://wwwtech.de).
Wenn du den Punkt escapen würdest, würde er nicht für ein beliebiges Zeichen stehen. :)
([A-Za-z0-9-]+.)*
Und ich zähle im Geiste mit: Teil 1 plus Punkt. Beliebig häufig, und optional.
([A-Za-z0-9-]{3,}.)
Hiermit definiere ich den Hauptteil der Domain. Der muss aus
wenigstens 3 Zeichen der bekannten Zeichenklasse bestehen.
Wer behauptet, daß "Hauptteile von Domains" immer drei Zeichen lang sein müssen? Die Denic fordert heute eine Mindestlänge von drei Zeichen, es gibt aber auch 2-Zeichen-Domains wie http://www.ix.de. Und unter .com sind 2-Zeichen-Domains auch möglich (wenngleich die wohl auch alle schon registriert sind).
Geistiger Zähler: "teil1.teil1.tl2." Ein 3-Zeichen Teil zwingend.
([a-zA-Z0-9-]+.)*
Dem Haupt-Teil der Domain folgen weitere Teile. Sie alle muessen
aus der benannten Zeichenklasse bestehen.
Geistiger Zähler: "teil1.teil1.tl2.teilweise3.teilw3." Beliebig viele weitere Bestandteile, auch optional.
([a-z]{2,})
Hiermit ist die Subdomain gemeint. Die muss aus wenigstens zwei
Zeichen bestehen.
Ein 2-Zeichen-Teil zwingend.
Geistiger Zähler: "teil1.teil1.tl2.teilweise3.teilw3.de"
Tja, das Ergebnis sieht nach einer gültigen Domain aus. Mir ist zwar die Sache mit dem "Hauptteil der Domain" nicht klar, aber irgendwie wird's schon matchen.
Man kann ja sogar Zahlen nehmen:
"123.123.123.123.de" geht. Nur ist das eben keine IP-Adresse.
Minimal muß eine Domain-Angabe sowas sein: "123.de"
Der Rest (Pfad, Query, Anker) ist ja eher ungefährlich (obwohl ich beim Query-String auch Großbuchstaben zulassen würde, rein instinktiv).
Wie repariert man das jetzt? Eine zweite Verzweigungsvariante für IP-Adressen einbauen.
IP-Adressen sind so relativ leicht erkennbar:
(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})
Die Zwangslänge der Second-Level-Domain würde ich einfach auf 2 Zeichen senken (1 Zeichen ist IIRC wirklich verboten), und danach keine weiteren Bestandteile mehr zulassen, nur noch davor.
Also:
!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|([A-Za-z0-9-]+.)*([A-Za-z0-9-]{2,}.)([a-z]{2,}))(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!
Sieht für mich irgendwie schöner aus.
Was noch fehlt: Wenn kein http-ftp-mailto angegeben wird, wird das auch nicht in den Link eingebaut. Sowas ist böse, weil es natürlich nicht funktioniert. Und das wird man kaum mit einem regulären Ausdruck durch Suchen/Ersetzen regeln können, sondern da muß weitere Programmlogik her.
preg_match ('!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|([A-Za-z0-9-]+.)*([A-Za-z0-9-]{2,}.)([a-z]{2,}))(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!',$text,$gefunden);
Im Array $gefunden stehen jetzt alle Klammerausdrücke, die der reguläre Ausdruck so produziert hat. Mit If-Abfragen und etwas Raten kann man fehlende Informationen hinzufügen und in einen schönen Link verwandeln. :)
Ich denke aber, das Thema ist noch nicht vollkommen ausdiskutiert. ;)
- Sven Rautenberg