需要一个好的正则表达式将URL转换为链接,但只留下现有的链接

时间:2008-11-13 14:56:00

标签: php html regex url

我有大量用户提交的内容。它是HTML,可能包含URL。其中一些已经<a>已经(如果用户不错),但有时用户很懒,只需输入www.something.com或最好http://www.something.com

我找不到一个像样的正则表达式来捕获URL但忽略紧靠双引号或'&gt;'右边的那些。有人有吗?

6 个答案:

答案 0 :(得分:15)

RegexBuddy的创建者Jan Goyvaerts向杰夫阿特伍德的博客written a response提供了解决杰夫问题的博客,并提供了一个很好的解决方案。

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

为了忽略“or”之后发生的匹配,您可以将(?<![">])添加到正则表达式的开头,这样就可以了

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

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

答案 1 :(得分:11)

这个线程像山丘一样古老,但我在处理自己的问题时遇到了它:也就是说,将任何网址转换为链接,但保留已经在锚标记内的任何网页。过了一会儿,这就是弹出的东西:

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

使用以下输入:

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>

只是想回馈一下来拯救某人。

答案 2 :(得分:10)

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

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

允许更多子域,并且还对标签运行更全面的检查。要将此应用于PHP的preg替换,您可以使用:

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

注意,我从正则表达式中删除了@,以便将其用作preg_replace的分隔符。无论如何,@很少会在URL中使用。

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

希望有所帮助。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

无耻的插件:你可以在这里(regular expression replace a word by a link)寻找灵感。

问题是要用某个链接替换某个单词,除非已经有链接。所以你遇到的问题或多或少都是一样的。

您需要的是一个匹配URL(代替单词)的正则表达式。最简单的假设是:URL(可选)以"http://""ftp://""mailto:"开头,只要没有空格字符,换行符,标记括号,就会持续或引号)。

当心,前面有很长的正则表达。不区分大小写。

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

请注意 - 这也会匹配技术无效的网址,并且会将thing.formatted.like.this识别为URL。如果它太不敏感,这取决于您的数据。如果您有返回误报的示例,我可以对正则表达式进行微调。

正则表达式将产生两个匹配组。第2组将包含匹配的东西,很可能是URL。第1组将包含空字符串或'href="'。您可以将其用作此匹配发生在现有链接的href参数的指示器,而您不必触摸该匹配。

一旦你确认这对你来说是正确的大部分时间(使用用户提供的数据,你永远无法确定),你可以分两步完成其余的工作,正如我提出的那样它在另一个问题:

  1. 围绕每个网址建立一个链接(除非匹配组1中有内容!)此生成双嵌套<a>标记已有链接。
  2. 扫描错误嵌套的<a>标记,删除最里面的标记

答案 5 :(得分:0)

要跳过现有的只需使用后视 - 将(?<!href=")添加到正则表达式的开头,所以它看起来像这样:

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

显然,这不是查找所有类型网址的完整解决方案,但这可以解决您弄乱现有网址的问题。