Поиск и подстановка ссылки

09 Янв 2015 / Дарья Рыбалтович

По ходу работы над сайтом у меня появилась задача сделать автоподстановку ссылки при выводе текста, как это делается вконтакте. Т.е., при редактировании ты вводишь текст типа http://site.com/blah-blah, а при выводе уже готового текста вместо этого подставляется ссылка http://site.com/blah-blah. Вообще это же решение годится и просто для получения значения ссылок из текста, для дальнейшей с ними работы (например получения контента с помощью file_get_contents()).

На поиск простого решения в Яндексе у меня ушло несколько часов. Может, конечно, я не там искала, и не тот запрос вводила. Но всем обычно надо наоборот, выцапать содержимое ссылки из тэга <а>.

Я знала, что ищу регулярные выражения, я в них не сильна, так что надеялась найти что-то похожее. Почитав инфу на форумах, определилась с функциями, которые нужны для поиска по шаблону - preg_match_all() и preg_replace(). Функция preg_match_all() подробно она описана тут. А вместо preg_replace() при работе с неопределнным числом вхождений удобнее использовать strtr(). Функция preg_match_all(), как и preg_match() выводет найденные значения в массив, разница в том, что preg_match() берет только первое значение из найденных, а preg_match_all() - все. На выходе мы получаем массив, который задается третьим параметром функции. Потом надо просто этот массив перебрать циклом и каждое вхожение обернуть ссылкой.

Короче, после долгих мучений я пришла к вот такому решению:

function find_link($str){
   if(strstr($str, "http://")){
      preg_match_all("#http://([^),\s\n]*)#", $str, $replace);
      foreach($replace[0] as $r){
         $arr[$r] = "<a href='$r'>$r</a>";
      }
      $res = strtr($str, $arr);
   }
   if($res != NULL) return $res;
      else return $str;
}

Стоит пояснить, что это такая особенность вывода preg_match_all(), значение выводится в массив $replace, но перебираем мы только первый элемент $replace[0], который является подмассивом, т.к. остальные элементы этого массива содержат уже распарсенную строку по разделителю, а нам нужна целая ссылка.

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

После выхода из цикла мы вызываем функцию strtr(), которая как раз и выполняем замену в тексте по шаблону. Причем, строкой поиска являются ключи массива, а строкой замены - их значения. Это очень удобно в случае. когда имеем неопределенное количество элементов для замены.

Теперь разберем регулярного выражение #http://([^),\s\n]*)#.

Символ #, которым оно обернуто, - просто символ, можно использовать любой другой / ~ кому на что фантазии хватит :) Типа как обозначение, что это начало и конец шаблона.

http://, указываем,что ищем вхождение с таким началом, оно не меняется.

Блок ([^),\s\n]*) нужен для того, чтобы найти конец ссылки. То есть мы берем все после http://, пока не встретим закрывающую круглую скобку ), запятую, пробельный символ \s или символ конца строки \n.

Это регулярное выражение будет работать для ссылок вида http://site.com/site, http://site.com/site.html, http://site.com/site/index.html и т.д. Для более длинных просто не проверяла.

В самом конце проверяем полученную строку и если она пусто - возвращаем то, что нам пришло на входе функции, т.е. исходную строку. 

Может, решение и не универсальное, т.к. если, например, в конце будет стоять точка (.), то она добавится в шаблон, и мы получим неправильную ссылку. Так что по-хорошему надо бы дописать проверку на концевой символ. Но это уже пусть дорабатывает кто-то другой. Моя задача была сделать быстренькую проверку и подстановку без тонн кода :)

Метки: PHP, Сайтостроение