需要一个很好的正则expression式来将URL转换为链接,但只保留现有的链接

我有一个用户提交的内容的负载。 它是HTML,可能包含URL。 他们中的一些将已经(如果用户是好的),但有时用户是懒惰的,只需键入www.something.com或至多http://www.something.com 。

我无法find一个体面的正则expression式来捕获url,但忽略立即在双引号或“>”右侧的url。 任何人都有一个?

RegexBuddy的创始人Jan Goyvaerts 写了一篇回应 Jeff Atwood的博客,解决了Jeff所提出的问题,并提供了一个很好的解决scheme。

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

为了忽略发生在“或”旁边的匹配,你可以添加(?<![">])到正则expression式的开头,所以你得到

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

这将匹配完整地址( http:// .. )和以www开头的地址。 或者ftp。 – 你的地址如ars.userfriendly.org运气不好

我对原始答案中包含的正则expression式做了一些修改:

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

它允许更多的子域名,并且对标签进行更全面的检查。 要将此应用于PHP的pregreplace,您可以使用:

 $convertedText = preg_replace( '@(?<![.*">])\b(?:(?:https?|ftp|file)://|[az]\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$]@i', '<a href="\0" target="_blank">\0</a>', $originalText ); 

请注意,我从正则expression式中删除了@,以便将它用作preg_replace的分隔符。 无论如何,@将很less用在URL中。

显然,你可以修改replace文本,并删除target =“_ blank”,或者添加rel =“nofollow”等。

希望有所帮助。

这个线程就像山丘一样古老,但是我在处理自己的问题的时候遇到了这个问题:也就是说,将任何url转换成链接,但是不要留下任何已经在锚定标记中的网页。 过了一段时间,这就是已经出现的情况:

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

通过以下input:

 http://www.google.com http://google.com www.google.com <p>http://www.google.com<p> this is a normal sentence. let's hope it's 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's hope it's ok. <a href="http://www.google.com">www.google.com</a> 

只是想回来节省一些人的时间。

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

无耻的插件:你可以看这里( 正则expression式replace一个字的链接 )的灵感。

除非已经存在链接,否则要求用某个链接replace某个词。 所以你的问题或多或less是一回事。

所有你需要的是一个正则expression式匹配一个URL(代替这个词)。 最简单的假设是这样的:URL(可选)以"http://""ftp://""mailto:"开头,只要没有空白字符,换行符,标签括号或引号)。

要小心,长远的正则expression式。 不区分大小写应用

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

被警告 – 这也将匹配在技术上无效的URL,它将识别东西.formatted.like.this作为一个URL。 这取决于你的数据,如果它太不敏感。 我可以微调正则expression式,如果你有例子返回误报。

正则expression式将产生两个匹配组。 组2将包含匹配的东西,这很可能是一个URL。 组1将包含一个空string或一个'href="' ,你可以用它作为一个指示符,这个匹配发生现有链接的一个href参数中,你不必触摸那个。

一旦你确认这在大多数情况下对你来说是正确的(用户提供的数据,你永远无法确定),你可以分两步完成,就像我在另一个问题中提出的那样:

  1. 在每个URL周围build立一个链接( 除非匹配组1中有东西!)这将为已经链接的东西生成双重嵌套的<a>标签。
  2. 扫描不正确的嵌套<a>标签,删除最内层的标签

要跳过现有的只是使用后视 – 添加(?<!href=")到正则expression式的开始,所以它看起来像这样:

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

显然,这不是一个完整的解决scheme来查找所有types的URL,但是这应该解决您现有的问题。