регулярное выражение регулярного выражения для соответствия большинству URL нуждается в улучшении - PullRequest
1 голос
/ 28 марта 2012

Мне нужна функция, которая будет проверять существующие URL-адреса в строке.

function linkcleaner($url) {
$regex="(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))";

if(preg_match($regex, $url, $matches)) {
echo $matches[0];
}
}

Регулярное выражение взято из блога Джона Грубера , где он решил проблему создания регулярного выражения, соответствующего всем URL-адресам. К сожалению, я не могу заставить это работать. Кажется, проблема в двойных кавычках внутри регулярного выражения или других пунктирных символах в конце выражения. Любая помощь приветствуется. Спасибо!

Ответы [ 4 ]

3 голосов
/ 28 марта 2012

Вам нужно сбежать " с \

2 голосов
/ 28 марта 2012

Помимо ответа @ tandu, вам также нужны разделители для регулярного выражения в php.

Самым простым будет начать и закончить ваш паттерн с #, так как этот символ не появляется в нем:

$regex="#(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'\".,<>?«»“”‘’]))#";
1 голос
/ 28 марта 2012

Я не уверен, как вы, ребята, читаете это регулярное выражение, потому что читать / изменять его очень сложно ...;)

попробуйте это (это не однострочный, да, но этолегко понять и изменить при необходимости):

<?php
$re_proto = "(?:https?|ftp|gopher|irc|whateverprotoyoulike)://";
$re_ipv4_segment = "[12]?[0-9]{1,2}";
$re_ipv4 = "(?:{$re_ipv4_segment}[.]){3}".$re_ipv4_segment;
$re_hostname = "[a-z0-9_]+(?:[.-][a-z0-9_]+){0,}";
$re_hostname_fqdn = "[a-z0-9_](?:[a-z0-9_-]*[.][a-z0-9]+){1,}";
$re_host = "(?:{$re_ipv4}|{$re_hostname})";
$re_host_fqdn = "(?:{$re_ipv4}|{$re_hostname_fqdn})";
$re_port = ":[0-9]+";
$re_uri = "(?:/[a-z0-9_.%-]*){0,}";
$re_querystring = "[?][a-z0-9_.%&=-]*";
$re_anchor = "#[a-z0-9_.%-]*";
$re_url = "(?:(?:{$re_proto})(?:{$re_host})|{$re_host_fqdn})(?:{$re_port})?(?:{$re_uri})?(?:{$re_querystring})?(?:{$re_anchor})?";

$text = <<<TEXT
http://www.example.com
http://www.example.com/some/path/to/file.php?f1=v1&f2=v2#foo
http://localhost.localdomain/
http://localhost/docs/???
www....wwhat?
www.example.com
ftp://ftp.mozilla.org/pub/firefox/latest/
Some new Mary-Kate Olsen pictures I found: the splendor of the Steiner Street Picture of href… http://t.co/tJ2NJjnf
TEXT;

$count = preg_match_all("\01{$re_url}\01is", $text, $matches);
var_dump($count);
var_dump($matches);
?>
1 голос
/ 28 марта 2012

Комментарий Джека Мани ... EPIC: D

На более серьезной ноте это не работает, потому что вы завершили строковый литерал прямо посередине.

Чтобы включить двойную кавычку(") в строке, вам нужно экранировать ее, используя \

Итак, строка будет

$regex="/(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'\".,<>?«»“”‘’]))/";

Обратите внимание, что я избежал (') также.Это для случаев, когда вы определяете строку между 2 одинарными кавычками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...