Нужно хорошее регулярное выражение для преобразования URL-адресов в ссылки, но оставить существующие ссылки в покое - PullRequest
20 голосов
/ 13 ноября 2008

У меня есть загруженный пользователем контент. Это HTML, и может содержать URL. Некоторые из них будут <a> уже (если пользователь хороший), но иногда пользователи ленивы и просто набирают www.something.com или в лучшем случае http://www.something.com.

Я не могу найти приличное регулярное выражение для захвата URL-адресов, но игнорирую те, которые находятся сразу справа от двойной кавычки или '>'. У кого-нибудь есть?

Ответы [ 6 ]

15 голосов
/ 13 ноября 2008

Ян Гойваэртс, создатель RegexBuddy , написал ответ в блог Джеффа Этвуда, в котором рассматриваются проблемы, возникшие у Джеффа, и предлагает хорошее решение.

\b(?:(?:https?|ftp|file)://|www\.|ftp\.)[-A-Z0-9+&@#/%=~_|$?!:,.]*[A-Z0-9+&@#/%=~_|$]

Чтобы игнорировать совпадения, которые происходят прямо рядом с "или>, вы можете добавить (?<![">]) к началу регулярного выражения, чтобы вы получили

(?<![">])\b(?:(?:https?|ftp|file)://|www\.|ftp\.)[-A-Z0-9+&@#/%=~_|$?!:,.]*[A-Z0-9+&@#/%=~_|$]

Это будет соответствовать полным адресам ( http: //...) И адресам, начинающимся с www. или ftp. - вам не повезло с такими адресами, как ars.userfriendly.org ...

11 голосов
/ 08 мая 2012

Эта ветка старая, как холмы, но я натолкнулся на нее, работая над своей собственной проблемой: то есть преобразовать любые ссылки в ссылки, но оставить в покое любые, которые уже находятся в тегах привязки. Через некоторое время вот что выскочило:

(?!(?!.*?<a)[^<]*<\/a>)(?:(?:https?|ftp|file)://|www\.|ftp\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$]

Со следующим вводом:

http://www.google.com
http://google.com
www.google.com

<p>http://www.google.com<p>

this is a normal sentence. let's hope it's ok.

<a href="http://www.google.com">www.google.com</a>

Это вывод preg_replace:

<a href="http://www.google.com" rel="nofollow">http://www.google.com</a>
<a href="http://google.com" rel="nofollow">http://google.com</a>
<a href="www.google.com" rel="nofollow">www.google.com</a>

<p><a href="http://www.google.com" rel="nofollow">http://www.google.com</a><p>

this is a normal sentence. let's hope it's ok.

<a href="http://www.google.com">www.google.com</a>

Просто хотел внести свой вклад, чтобы спасти кого-нибудь.

10 голосов
/ 01 июня 2010

Я внес небольшое изменение в регулярное выражение, содержащееся в исходном ответе:

(?<![.*">])\b(?:(?:https?|ftp|file)://|[a-z]\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$]

, который учитывает больше поддоменов, а также выполняет более полную проверку тегов. Чтобы применить это к preg replace в PHP, вы можете использовать:

$convertedText = preg_replace( '@(?<![.*">])\b(?:(?:https?|ftp|file)://|[a-z]\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$]@i', '<a href="\0" target="_blank">\0</a>', $originalText );

Обратите внимание, я удалил @ из регулярного выражения, чтобы использовать его в качестве разделителя для preg_replace. Довольно редко @ будет использоваться в URL в любом случае.

Очевидно, что вы можете изменить текст замены и удалить target = "_ blank" или добавить rel = "nofollow" и т. Д.

Надеюсь, это поможет.

1 голос
/ 22 июня 2012
if (preg_match('/\b(?<!=")(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[A-Z0-9+&@#\/%=~_|](?!.*".*>)(?!.*<\/a>)/i', $subject)) {
    # Successful match
} else {
    # Match attempt failed
}
0 голосов
/ 24 февраля 2010

Чтобы пропустить существующие, просто используйте оглядку назад - добавьте (?<!href=") в начало вашего регулярного выражения, чтобы оно выглядело примерно так:

/(?<!href=")http://\S*/

Очевидно, что это не полное решение для поиска всех типов URL, но это должно решить вашу проблему с путаницей с существующими.

0 голосов
/ 13 ноября 2008

Бесстыдный плагин: Вы можете посмотреть здесь ( регулярное выражение заменяет слово ссылкой ) для вдохновения.

Вопрос, заданный для замены какого-либо слова на определенную ссылку, если только ссылки не было. Так что проблема у вас более или менее та же самая.

Все, что вам нужно, это регулярное выражение, которое соответствует URL (вместо слова). Самое простое предположение было бы таким: URL (необязательно) начинается с "http://", "ftp://" или "mailto:" и длится до тех пор, пока нет пробелов, разрывов строк, скобок тегов или кавычек).

Осторожно, впереди длинное регулярное выражение. Применить без учета регистра.

(href\s*=\s*['"]?)?((?:http://|ftp://|mailto:)?[^.,<>"'\s\r\n\t]+(?:\.(?![.<>"'\s\r\n])[^.,!<>"'\s\r\n\t]+)+)

Имейте в виду - это также будет соответствовать URL-адресам, которые технически недействительны, и будет распознавать в качестве URL-адреса things.formatted.like.this. Это зависит от ваших данных, если они слишком нечувствительны. Я могу точно настроить регулярное выражение, если у вас есть примеры, когда он возвращает ложные срабатывания.

Регламент создаст две группы совпадений. Группа 2 будет содержать соответствующую вещь, которая, скорее всего, является URL. Группа 1 будет содержать либо пустую строку, либо 'href="'. Вы можете использовать его как индикатор того, что это совпадение произошло внутри параметра href существующей ссылки, и вам не нужно прикасаться к нему.

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

  1. Создайте ссылку вокруг каждого URL-адреса (, если не найдет что-то в группе совпадений 1!). создаст двойные вложенные теги <a> для вещей, которые уже имеют ссылку .
  2. Сканирование на наличие неправильно вложенных тегов <a>, удаление самой внутренней
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...