【问题标题】:PHP / RegEx - Convert URLs to links by detecting .com/.net/.org/.edu etcPHP / RegEx - 通过检测 .com/.net/.org/.edu 等将 URL 转换为链接
【发布时间】:2012-04-11 16:57:09
【问题描述】:

我知道有很多问题要求帮助将 URL 转换为字符串中的可点击链接,但我还没有找到我要找的东西。

我希望能够匹配以下任何示例并将它们变成可点击的链接:

http://www.domain.com
https://www.domain.net
http://subdomain.domain.org
www.domain.com/folder
subdomain.domain.net
subdomain.domain.edu/folder/subfolder
domain.net
domain.com/folder

我不想匹配 random.stuff.separated.with.periods。

编辑:请记住,这些 URL 需要在较大的“普通”文本字符串中找到。例如,我想在“Hello!Come check out domain.net!”中匹配“domain.net”。

我认为这可以通过一个正则表达式来完成,该表达式可以确定匹配的 url 是否包含 .com、.net、.org 或 .edu,后跟正斜杠或空格。除了用户拼写错误之外,我无法想象在任何其他情况下,一个有效的 URL 会包含其中一个,然后是其他任何内容。

我知道有很多有效的域扩展,但我不需要全部支持。我可以在正则表达式中选择支持 (com|net|org|edu) 之类的内容。不幸的是,我对正则表达式还不够熟练,还不知道如何正确实现它。

我希望有人可以帮助我找到一个正则表达式(用于 PHP 的 preg_replace),它可以匹配基于由一个或多个点连接的几乎任何文本的 URL,并且以指定的扩展名之一结尾,后跟空格或包含指定的扩展名之一,后跟斜杠和可能的文件夹。

我进行了几次搜索,但到目前为止还没有找到我要查找的内容。如果已经存在回答此问题的 SO 帖子,我深表歉意。

提前致谢。

--- 编辑 3 ---

经过几天的反复试验和 SO 的帮助,以下是有效的方法:

preg_replace_callback('#(\s|^)((https?://)?(\w|-)+(\.(\w+|-)*)+(?<=\.net|org|edu|com|cc|br|jp|dk|gs|de)(\:[0-9]+)?(?:/[^\s]*)?)(?=\s|\b)#is',
                create_function('$m', 'if (!preg_match("#^(https?://)#", $m[2]))
                return $m[1]."<a href=\"http://".$m[2]."\">".$m[2]."</a>"; else return $m[1]."<a href=\"".$m[2]."\">".$m[2]."</a>";'),
                $event_desc);

这是下面 anubhava 代码的修改版本,到目前为止似乎完全符合我的要求。谢谢!

【问题讨论】:

标签: php regex url hyperlink


【解决方案1】:

你可以使用这个正则表达式:

#(\s|^)((?:https?://)?\w+(?:\.\w+)+(?<=\.(net|org|edu|com))(?:/[^\s]*|))(?=\s|\b)#is

代码:

$arr = array(
'http://www.domain.com/?foo=bar',
'http://www.that"sallfolks.com',
'This is really cool site: https://www.domain.net/ isn\'t it?',
'http://subdomain.domain.org',
'www.domain.com/folder',
'Hello! You can visit vertigofx.com/mysite/rocks for some awesome pictures, or just go to vertigofx.com by itself',
'subdomain.domain.net',
'subdomain.domain.edu/folder/subfolder',
'Hello! Check out my site at domain.net!',
'welcome.to.computers',
'Hello.Come visit oursite.com!',
'foo.bar',
'domain.com/folder',

);
foreach($arr as $url) {   
   $link = preg_replace_callback('#(\s|^)((?:https?://)?\w+(?:\.\w+)+(?<=\.(net|org|edu|com))(?:/[^\s]*|))(?=\s|\b)#is',
           create_function('$m', 'if (!preg_match("#^(https?://)#", $m[2]))
               return $m[1]."<a href=\"http://".$m[2]."\">".$m[2]."</a>"; else return $m[1]."<a href=\"".$m[2]."\">".$m[2]."</a>";'),
           $url);
   echo $link . "\n";

输出:

<a href="http://www.domain.com/?foo=bar">http://www.domain.com/?foo=bar</a>
http://www.that"sallfolks.com
This is really cool site: <a href="https://www.domain.net">https://www.domain.net</a>/ isn't it?
<a href="http://subdomain.domain.org">http://subdomain.domain.org</a>
<a href="http://www.domain.com/folder">www.domain.com/folder</a>
Hello! You can visit <a href="http://vertigofx.com/mysite/rocks">vertigofx.com/mysite/rocks</a> for some awesome pictures, or just go to <a href="http://vertigofx.com">vertigofx.com</a> by itself
<a href="http://subdomain.domain.net">subdomain.domain.net</a>
<a href="http://subdomain.domain.edu/folder/subfolder">subdomain.domain.edu/folder/subfolder</a>
Hello! Check out my site at <a href="http://domain.net">domain.net</a>!
welcome.to.computers
Hello.Come visit <a href="http://oursite.com">oursite.com</a>!
foo.bar
<a href="http://domain.com/folder">domain.com/folder</a>

PS: 此正则表达式仅支持 URL 中的 http 和 https 方案。例如:如果你也想支持 ftp,那么你需要稍微修改一下正则表达式。

【讨论】:

  • 谢谢。不幸的是,这根本没有检测到 URL。请记住,需要在普通文本块中找到 URL。例如,我需要在“您好!在 domain.net 上查看我的网站!”之类的内容中匹配“domain.net”
  • 从您的示例来看,您似乎只有一个 URL 列表。无论如何,现在很清楚,我刚刚编辑了请检查我的答案。
  • 谢谢。您的新正则表达式更接近,除了有两个问题。没有 http:// 的 URL 会被转换为相对链接,例如,something.domain.net 的 URL 会变成像 vertigofx.com/something.domain.net 这样的链接(假设我的页面托管在 'www.vertigofx.com')自己的绝对链接。此外,当它匹配一个带有文件夹路径的 URL 时,它后面还会包含一些其他内容。
  • 好的,我根据您的 cmets 再次编辑了我的答案,请现在检查。
  • 我发现了一个矛盾的问题。我在做 preg_replace 之前使用了 nl2br(),所以行尾有
    标签,通常直接在 URL 之后。我解决了这个问题,你的正则表达式工作得更好,但它仍然不理想。如果我输入“welcome.to.computers”它匹配“welcome.to.com”,它不应该。我意识到有人不太可能键入正确的点和字母组合来创建错误的 URL,但必须有一种方法来修复它。你能不能让它必须以空格或正斜杠结尾才能匹配?
【解决方案2】:
'/(http(s)?:\/\/)?[\w\/\.]+(\.((com)|(edu)|(net)|(org)))[\w\/]*/'

这适用于您的示例。您可能希望在最后一个括号中添加对“-”、“&”、“?”、“:”等的额外字符支持。

'/(http(s)?:\/\/)?[\w\/\.]+(\.((com)|(edu)|(net)|(org)))[\w\/\?=&-;]*/'

这将支持参数和端口号。

例如:www.foo.ca:8888/test?param1=val1&param2=val2

【讨论】:

  • 感谢您的帮助。我尝试了您的第二个示例并收到有关未知修饰符“?”的 PHP 警告。在 preg_replace
  • 然后试试 '/(http(s)?:\/\/)?[\w\/\.]+(\.((com)|(edu)|(net)| (org)))[\w\/\?=&-;]*/'
  • 这几乎可以完美运行!谢谢你。现在唯一的问题是我在使用 anubhava 的解决方案时遇到的问题之一。开头没有“http://”的 URL 将作为相对链接出现。当然,我可能会测试它是否存在,如果不存在则添加它。我认为这会做到。如果出现任何问题,我会通知您。编辑:啊,刚刚发现一个问题。正则表达式匹配一个以 .edue 结尾的字符串,但它不应该匹配。如何修改正则表达式,使其要求扩展名后紧跟空格或斜杠?
  • 我使用 preg_replace_callback() 来包含一个函数,该函数将“http://”添加到缺少它的链接中。现在,我只需要一些关于将 URL 与这些扩展名匹配的帮助,前提是扩展名后跟空格或斜杠(以防止匹配“Hello.Come visit oursite.com!”中的“.Com”之类的内容!
  • '/(http(s)?:\/\/)?[\w\/\.]+(\.((com)|(edu)|(net)|(org) )))[^\w.]{1}[\w\/\?=&-;]*/' 应该阻止“教育”。对于最后一个字符,我猜你可以验证它。
【解决方案3】:

非常感谢。我修改了他的最终解决方案以允许所有域(.ca、.co.uk),而不仅仅是指定的域。

$html = preg_replace_callback('#(\s|^)((https?://)?(\w|-)+(\.[a-z]{2,3})+(\:[0-9]+)?(?:/[^\s]*)?)(?=\s|\b)#is',
    create_function('$m', 'if (!preg_match("#^(https?://)#", $m[2])) return $m[1]."<a href=\"http://".$m[2]."\" target=\"blank\">".$m[2]."</a>"; else return $m[1]."<a href=\"".$m[2]."\" target=\"blank\">".$m[2]."</a>";'),
    $url);

【讨论】:

  • 我不太擅长正则表达式。您是如何设法确定有效域名的结尾和打错句子的结尾/开头之间的区别的?比如“subdomain.domain.ca”和“Hey.Hello.Can you read this?”的区别
猜你喜欢
  • 1970-01-01
  • 2014-05-11
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2012-06-15
  • 1970-01-01
  • 2015-04-22
相关资源
最近更新 更多