Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Ян Гойваертс, создатель 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...

Ответ 2

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

(?!(?!.*?<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 hope it 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 hope it ok.

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

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

Ответ 3

Я сделал небольшую модификацию в Regex, содержащуюся в исходном ответе:

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

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

$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" и т.д.

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

Ответ 4

if (preg_match('/\b(?<!=")(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[A-Z0-9+&@#\/%=~_|](?!.*".*>)(?!.*<\/a>)/i', $subject)) {
    # Successful match
} else {
    # Match attempt failed
}

Ответ 5

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

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

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

Остерегайтесь длинного регулярного выражения. Примените регистр-insensitively.

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

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

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

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

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

Ответ 6

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

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

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