Я пытаюсь преобразовать из ввода 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. Ни одно из решений, представленных здесь (пока), в этом случае будет безопасным.
https?://
и заканчивается пробелом или концом строки ( вертикальное пространство или так называемая новая строка ). <a href=" http...">
начинается с пробела, но это недопустимо html ) , /m
сообщает регулярному выражению, чтобы он соответствовал каждой строке ( так что работа, описанная в первой точке, будет работать ). nl2br()
должна использоваться после замены ( из-за ссылок, начинающихся в начале строки ). <?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; }
Некоторые дополнительные советы:
Это было сделано сотни раз раньше. На этой странице m-buettner и glavić работают нормально, хотя мне нравится более яркое выражение лица.
Вот хороший ресурс php для этого: http://code.iamcal.com/php/lib_autolink/
Повторяет на Stackoverflow:
Достойная углубленная статья: http://buildinternet.com/2010/05/how-to-automatically-linkify-text-with-php-regular-expressions/