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

Я пытаюсь преобразовать URL-адреса в фрагмент текста в гиперссылки – используя регулярные выражения. Мне удалось достичь этого, но проблема в том, что в тексте уже есть ссылки

так

bla bla blah www.google.com bla blah <a href="www.google.com">www.google.com</a> 

должно привести к

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

не

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

Solutions Collecting From Web of "регулярное выражение, чтобы превращать URL-адреса в ссылки, не вступая в связь с существующими ссылками в тексте"

Наконец закончил:

 function add_url_links($data) { $data = preg_replace_callback('/(<a href=.+?<\/a>)/','guard_url',$data); $data = preg_replace_callback('/(http:\/\/.+?)([ \\n\\r])/','link_url',$data); $data = preg_replace_callback('/^(http:\/\/.+?)/','link_url',$data); $data = preg_replace_callback('/(http:\/\/.+?)$/','link_url',$data); $data = preg_replace_callback('/{{([a-zA-Z0-9+=]+?)}}/','unguard_url',$data); return $data; } function guard_url($arr) { return '{{'.base64_encode($arr[1]).'}}'; } function unguard_url($arr) { return base64_decode($arr[1]); } function link_url($arr) { return guard_url(array('','<a href="'.$arr[1].'">'.$arr[1].'</a>')).$arr[2]; } 

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

 state = OUTSIDE_LINK for pos (0 .. length input) switch state case OUTSIDE_LINK if substring at pos matches /<a/ state = INSIDE_LINK else if substring at pos matches /(www.\S+|\S+.com|\S+.org)/ substitute link case INSIDE_LINK if substring at post matches /<\/a>/ state = OUTSIDE_LINK 

Другой способ сделать это (в php)

  $strParts = preg_split( '/(<[^>]+>)/', $html, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); foreach( $strParts as $key=>$part ) { /*check this part isn't a tag or inside a link*/ if( !(preg_match( '@(<[^>]+>)@', $part ) || preg_match( '@(<a[^>]+>)@', $strParts[$key - 1] )) ) { $strParts[$key] = preg_replace( '@((http(s)?://)?(\S+\.{1}[^\s\,\.\!]+))@', '<a href="http$3://$4">$1</a>', $strParts[$key] ); } } $html = implode( $strParts ); 

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

 $data = 'test http://foo <a href="http://link">LINK</a> test'; $data = preg_replace_callback('/(<a href=".+?<\/a>)/','guard_url',$data); $data = preg_replace_callback('/(http:\/\/.+?)([ .\\n\\r])/','link_url',$data); $data = preg_replace_callback('/{{([a-zA-Z0-9+]+?)}}/','unguard_url',$data); print $data; function guard_url($arr) { return '{{'.base64_encode($arr[1]).'}}'; } function unguard_url($arr) { return base64_decode($arr[1]); } function link_url($arr) { return '<a href="'.$arr[1].'">'.$arr[1].'</a>'.$arr[2]; } 

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