конвертировать url в ссылки из строки, за исключением случаев, когда они находятся в атрибуте тега html

Я пытаюсь преобразовать из ввода textarea ( $_POST['content'] ), все URL-адреса для ссылки.

 $content = preg_replace('!(\s|^)((https?://)+[a-z0-9_./?=&-]+)!i', ' <a href="$2" target="_blank">$2</a> ', nl2br($_POST['content'])." "); $content = preg_replace('!(\s|^)((www\.)+[a-z0-9_./?=&-]+)!i', '<a target="_blank" href="http://$2" target="_blank">$2</a> ', $content." "); 

Целевые форматы ссылок: www.hello.com или http(s)://(www).hello.com

Но это, похоже, нарушает любой iframe, изображение или подобное,

Как есть / – правильное регулярное выражение, которое будет игнорировать URL-адреса в html-тегах?

Примечание. Я знаю, что мне нужно два выражения; один из них не обнаруживает никаких протокольных ссылок (например, www.hello.com , поэтому мне нужно добавить его), а другой – для обнаружения URL-адресов с протоколом (поэтому нет необходимости добавлять).

Ваш код в этом случае не должен быть проблемой внутри iframe и т. Д., Потому что там у вас обычно есть " перед вашим URL-адресом, а не с пространством, как того требует ваш шаблон».

Однако здесь есть другое решение. Он может не работать на 100%, если у вас есть одиночные < или > комментарии HTML или что-то подобное. Но в любом другом случае он должен хорошо вас обслуживать (и я не делаю это для вас проблемой или нет). Он использует отрицательный результат, чтобы убедиться, что закрытие > перед любым открытием < (потому что это означает, что вы находитесь внутри тега).

 $content = preg_replace('$(\s|^)(https?://[a-z0-9_./?=&-]+)(?![^<>]*>)$i', ' <a href="$2" target="_blank">$2</a> ', $content." "); $content = preg_replace('$(\s|^)(www\.[a-z0-9_./?=&-]+)(?![^<>]*>)$i', '<a target="_blank" href="http://$2" target="_blank">$2</a> ', $content." "); 

Если вы не знакомы с этой техникой, вот немного более подробная информация.

 (?! # starts the lookahead assertion; now your pattern will only match, if this subpattern does not match [^<>] # any character that is neither < nor >; the > is not strictly necessary but might help for optimization * # arbitrary many of those characters (but in a row; so not a single < or > in between) > # the closing > ) # ends the lookahead subpattern 

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

Если вам не нужен первый подшаблон (\s|^) для URL-адресов за пределами тегов, вы также можете удалить его (и уменьшить переменные захвата при замене).

 $content = preg_replace('$(https?://[a-z0-9_./?=&-]+)(?![^<>]*>)$i', ' <a href="$1" target="_blank">$1</a> ', $content." "); $content = preg_replace('$(www\.[a-z0-9_./?=&-]+)(?![^<>]*>)$i', '<a target="_blank" href="http://$1" target="_blank">$1</a> ', $content." "); 

И наконец … вы намерены не заменять URL-адреса, содержащие концевые ссылки в конце? Например: www.hello.com/index.html#section1 ? Если вы случайно это пропустили, добавьте # к вашим допустимым URL-адресам:

 $content = preg_replace('$(https?://[a-z0-9_./?=&#-]+)(?![^<>]*>)$i', ' <a href="$1" target="_blank">$1</a> ', $content." "); $content = preg_replace('$(www\.[a-z0-9_./?=&#-]+)(?![^<>]*>)$i', '<a target="_blank" href="http://$1" target="_blank">$1</a> ', $content." "); 

EDIT: Также, что относительно + и % ? Также есть несколько других символов, которые могут отображаться в URL-адресе без кодирования. Видеть это. КОНЕЦ РЕДАКТИРОВАНИЯ

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

Последняя мысль. Правильным решением было бы использовать парсер DOM . Тогда вы можете просто применить регулярное выражение, которое у вас уже есть, только для текстовых узлов. Тем не менее, ваша забота о структуре HTML очень ограничена, и это снова делает вашу проблему регулярной (если у вас нет комментариев «HTML» или JavaScript или CSS на странице). Если у вас есть эти особые случаи, вы должны действительно заглянуть в парсер DOM. Ни одно из решений, представленных здесь (пока), в этом случае будет безопасным.

  1. На мой взгляд, url – это все, что начинается с https?:// и заканчивается пробелом или концом строки ( вертикальное пространство или так называемая новая строка ).
  2. Из-за первой точки изображения, ссылки и т. Д. Не будут заменены, потому что все они начинаются с «или> ( за исключением того, что ссылка <a href=" http..."> начинается с пробела, но это недопустимо html ) ,
  3. Модификатор /m сообщает регулярному выражению, чтобы он соответствовал каждой строке ( так что работа, описанная в первой точке, будет работать ).
  4. Функция nl2br() должна использоваться после замены ( из-за ссылок, начинающихся в начале строки ).
  5. Пробелы до и после добавляются только в том случае, если пространство первоначально существует в $ content ( см. $ 1 и $ 3 во втором параметре функции preg_replace () ).
  6. Это решение поддерживает имена доменов со специальными символами , такими как http://www.moški.si .

Входные данные:

ВХОД

Код:

 <?php $content = preg_replace( '~(\s|^)(https?://.+?)(\s|$)~im', '$1<a href="$2" target="_blank">$2</a>$3', $content ); $content = preg_replace( '~(\s|^)(www\..+?)(\s|$)~im', '$1<a href="http://$2" target="_blank">$2</a>$3', $content ); $content = nl2br($content); 

Вывод:

Вывод

Редактировать:

Пример ссылок без https?:// preg_replace() + пример одиночного preg_replace() (шаблоны и замены – это массив):

 $content = preg_replace( array( '~(\s|^)(www\..+?)(\s|$)~im', '~(\s|^)(https?://)(.+?)(\s|$)~im', ), array( '$1http://$2$3', '$1<a href="$2$3" target="_blank">$3</a>$4', ), $content ); $content = nl2br($content); 

введите описание изображения здесь

Позвольте мне предложить что-то менее прямолинейное: разделите текст ввода на части html и non-html, а затем обработайте части, отличные от html, с вашим регулярным выражением, объединяющим текст обратно в одну часть. Что-л. как:

  <?php $chunks = preg_split('/(<.*>)/Ums', $_POST['content'], -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); $result = ''; foreach ($chunks as $chunk) { if (substr($chunk,0,1) != '<') { /* do your processing on $chunk */ } $result .= $chunk; } 

Некоторые дополнительные советы:

  1. попробуйте сохранить исходный текст и выполнить преобразование при его отображении. Это позволит вам улучшить / исправить код рендеринга, если в будущем вы найдете новую проблему / идею.
  2. (https?: //) + не должно быть в скобках, и вам не нужно +, потому что оно соответствует «https: // https: //some.com» – просто поместите https?: // [a-z0 -9_./?=&-]+
  3. то же самое (www.) + 🙂

Это было сделано сотни раз раньше. На этой странице m-buettner и glavić работают нормально, хотя мне нравится более яркое выражение лица.

Вот хороший ресурс php для этого: http://code.iamcal.com/php/lib_autolink/

Повторяет на Stackoverflow:

  • Как связать URL-адреса в строке с php?
  • PHP Связывание ссылок в контенте

Достойная углубленная статья: http://buildinternet.com/2010/05/how-to-automatically-linkify-text-with-php-regular-expressions/