需要一个很好的正则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参数中,你不必触摸那个。
一旦你确认这在大多数情况下对你来说是正确的(用户提供的数据,你永远无法确定),你可以分两步完成,就像我在另一个问题中提出的那样:
- 在每个URL周围build立一个链接( 除非匹配组1中有东西!)这将为已经链接的东西生成双重嵌套的
<a>
标签。 - 扫描不正确的嵌套
<a>
标签,删除最内层的标签
要跳过现有的只是使用后视 – 添加(?<!href=")
到正则expression式的开始,所以它看起来像这样:
/(?<!href=")http://\S*/
显然,这不是一个完整的解决scheme来查找所有types的URL,但是这应该解决您现有的问题。