regexen zum urlersetzen
Thomas Tschernich
- php
Ok, gibt's oft, aber ich such auch nicht ein regexp für url->link, sondern eins welches mir URLs, die ein naiver User ohne http:// eingibt, eben um jenes ergänzt. Er soll also alles von nem www bis zum nächsten Space erkennen und davor ein http:// setzen (bei Subdomains kann das nicht funktionieren und soll es auch nicht). Folgenden Pattern hab ich mir selbst zusammengemixt, der allerdings nicht ganz perfekt läuft:
=\A|\s([wW]{3}.[a-zA-Z0-9]+.[a-zA-Z]{2,4}[\S]*)=
Ersetzt werden würde der Treffer durch folgenden Term:
http://\1
Wie gesagt, funktioniert, nur klaut er mir das Leerzeichen vor der URL, also wird z.B. aus "test www.zeitz.net" -> "testhttp://www.zeitz.net", was mir logischerweise nicht viel bringt.
Was mach ich falsch und wie mach ichs besser?
Hi,
=\A|\s([wW]{3}.[a-zA-Z0-9]+.[a-zA-Z]{2,4}[\S]*)=
Dir ist bewusst, dass auch das (z.B.) \s hier mitersetzt wird? Beschäftige Dich mit Zerowidth-Lookahead, oder am besten gleich mit der Bedeutung von \b.
Wie gesagt, funktioniert,
_Leidlich_, würde ich sagen. Gegen die ich-hab-jetzt-auch-ne-k3wle-URL-User könnte es reichen; abgesehen von denen, die z.B. www.blablub.de.vu angeben. Übrigens: Der Bindestrich ist in Hostsegmenten ebenfalls erlaubt.
Cheatah
Hi,
=\A|\s([wW]{3}.[a-zA-Z0-9]+.[a-zA-Z]{2,4}[\S]*)=
Dir ist bewusst, dass auch das (z.B.) \s hier mitersetzt wird? Beschäftige Dich mit Zerowidth-Lookahead, oder am besten gleich mit der Bedeutung von \b.
Is ja eben das Problem ... ich bräuchte ne Art if da drin, d.h. dass vor der URL entweder der Anfang (\A) des Strings is, dieser nicht mit einbegriffen wird, oder ein Leerzeichen (\s), dass aber einbegriffen wird. Das ist das Problem.
Wie gesagt, funktioniert,
_Leidlich_, würde ich sagen. Gegen die ich-hab-jetzt-auch-ne-k3wle-URL-User könnte es reichen; abgesehen von denen, die z.B. www.blablub.de.vu angeben. Übrigens: Der Bindestrich ist in Hostsegmenten ebenfalls erlaubt.
Mein Ziel ist lediglich, die vielen User zu bremsen, die eine URL ohne http:// eingeben. Die Regexps zum Umwandlen in einen Link sollten dann unproblematisch sein, außerdem findet man die überall.
Hi,
Dir ist bewusst, dass auch das (z.B.) \s hier mitersetzt wird? Beschäftige Dich mit Zerowidth-Lookahead, oder am besten gleich mit der Bedeutung von \b.
Is ja eben das Problem ... ich bräuchte ne Art if da drin, d.h. dass vor der URL entweder der Anfang (\A) des Strings is, dieser nicht mit einbegriffen wird, oder ein Leerzeichen (\s), dass aber einbegriffen wird. Das ist das Problem.
die Lösung(en) habe ich Dir oben genannt.
Mein Ziel ist lediglich, die vielen User zu bremsen, die eine URL ohne http:// eingeben.
Dann nimm die RFC-1738-konforme 8-Kilobyte-RegExp, die hier regelmäßig zitiert wird, und setze hinter das "http(?:s)?://" ein Fragezeichen. Dadurch ist es optional. Wisse, dass dann - selbst wenn Du die Generik der Top-Level-Domains durch eine vollständige Liste ersetzt - auch Dummtipper wie "Ich biete was Tolles an.Info unter ..." plötzlich einen Link vor sich sehen.
Cheatah
Hallo, Cheatah,
ich habe eine ähnliche Frage, deswegen hänge ich mich einfach mal hier dran anstatt einen neuen Thread aufzumachen.
Dir ist bewusst, dass auch das (z.B.) \s hier mitersetzt wird? Beschäftige Dich mit Zerowidth-Lookahead, oder am besten gleich mit der Bedeutung von \b.
Ich beschäftige mich gerade auch mit lookahead und lookbehind assertations, ich habe es vor einiger Zeit einmal durchblickt (d.h. ich konnte das realisieren, was ich wollte, von durchblicken jede Spur) aber wieder vergessen.
Mein Problem ist: Ich möchte alle in < und > eingefassten Bestandteile eines Strings finden. Hm, okay, dafür wäre auch ~<[^>]+>~ passend, aber mir geht es auch eher generell um RegExps, deshalb etwas kniffliger.
$murks='murks';
$string='murks1 murks2 murks3 murks4 <murks5 murks6 > murks7 murks8 <murks9> < murks10> murks11 <murks12> murks13 <murks>';
preg_replace('~(?!<)(?=[^<]*?)'.$murks.'(?<=[^>]*?)(?<!>)~U', 'purks', $string);
Testweise soll hier jedes murks, was innerhalb < und > steht, durch purks ersetzt werden, der String sollte nach dem Ersetzen so aussehen:
murks1 murks2 murks3 murks4 <purks5 purks6 > murks7 murks8 <purks9> < purks10> murks11 <purks12> murks13 <purks>
(murks und purks sind meine metasyntaktischen Variablen, ähnlich foo und bar. ;))
Obige lookahead/-behind assertations gehen natürlich nicht, weil sie eine undefinierte Länge haben. Nun dachte ich daran, auf selbige zu verzichten:
preg_replace('~(<)([^<]*)('.$murks.')([^>]*)(>)~U', '\1\2purks\4\5', $string);
Damit wird aber murks6 nicht gefunden... ohne das ungreedy geht übrigens gar nichts richtig... sehr seltsam, denn die RegExp matcht durchaus mehrfach, aber nicht an der richtigen Stelle... ich habe es aber nicht detailliert untersucht.
Nicht dass es sonderlichen praktischen Wert hat, aber mich würde es schon interessieren, wie man das lösen könnte... die lookbehind/-ahead assertations sind doch richtig verwendet, wenn man von dem * absieht?
BTW, kannst du mir ein Beispiel für den Unterschied zwischen ^und \A und $ und \Z geben (wenn der i pattern modifier gesetzt ist) - mir war nämlich bisher nur ^ und $ bekannt.
Kennst du zufällig eine deutsche Übersetzung der PCRE pattern syntax... die Originalversion hat nahezu keine verständlichen Beispiele.
Grüße,
Mathias
Hallo Mathias,
BTW, kannst du mir ein Beispiel für den Unterschied zwischen ^und \A und $ und \Z geben (wenn der i pattern modifier gesetzt ist) - mir war nämlich bisher nur ^ und $ bekannt.
i-Modifier = case-insensitive; was hat das denn damit zu tun?
Es gibt nur einen Unterschied mit dem m-Modifier.
$string = "hallo
ciao";
preg_match("/\Ahallo\Z/m", $string) => false
preg_match("/\Aciao\Z/m", $string) => false
preg_match("/^hallo$/m", $string) => true
preg_match("/^ciao$/m", $string) => true
preg_match("/\Ahallo\nciao\Z/m", $string) => true
preg_match("/^hallo\nciao$/m", $string) => false
-----
preg_match("/\Ahallo\nciao\Z/m", $string) => true
preg_match("/^hallo\nciao$/m", $string) => true
preg_match("/\Ahallo\Z/m", $string) => false
preg_match("/\Aciao\Z/m", $string) => false
preg_match("/^hallo$/m", $string) => false
preg_match("/^ciao$/m", $string) => false
Alles klar?
Grüße,
Christian