0

使用以下代码将消息中的 URL 转换为 HTML 链接:

$message = preg_replace("#(http|https|ftp|ftps)://([.]?[&;%=a-zA-Z0-9_/?-])*#",
    "<a href=\"away?to=\\0\" target=\"_blank\">\\0</a>", $message);

$message = preg_replace("#(^| |\n)(www([.]?[&;%=a-zA-Z0-9_/?-])*)#",
    "\\1<a href=\"away?to=http://\\2\" target=\"_blank\">\\2</a>", $message);

它适用于几乎所有链接,但以下情况除外:

1) http://example.com/mediathek#/video/1976914/zoom:-World-Wide

这里的问题是链接内的#:,因为没有转换完整的链接。

2) If someone just writes "www" in a message

例子:<a href="http://www">www</a>

所以问题是在上面的代码中是否有任何方法可以解决这两种情况

4

3 回答 3

2

由于您想将哈希( #) 包含到正则表达式中,因此您需要将分隔符更改为不包含在正则表达式中的字符,例如!. 因此,您的正则表达式应如下所示:

$message = preg_replace("!(http|https|ftp|ftps)://([.]?[&;%#:=a-zA-Z0-9_/?-])*!",
"<a href=\"away?to=\\0\" target=\"_blank\">\\0</a>", $message);

这有帮助吗?

但是,如果您希望更符合规范 ( RCF 1738 ),您可能希望排除%URL 中不允许的内容。还有一些您未包含的允许字符:

  • $
  • _
  • . (点)
  • +
  • *
  • '
  • (
  • )

如果要包含这些字符,则应使用%.

于 2013-10-30T21:49:45.287 回答
1

几个小的调整。\#将and添加:到第一个正则表达式,然后在第二个正则表达式中更改*为:+

$message = preg_replace("#(http|https|ftp|ftps)://([.]?[&;%=a-zA-Z0-9_/?\#:-])*#",
    "<a href=\"away?to=\\0\" target=\"_blank\">\\0</a>", $message);

$message = preg_replace("#(^| |\n)(www([.]?[&;%=a-zA-Z0-9_/?-])+)#",
    "\\1<a href=\"away?to=http://\\2\" target=\"_blank\">\\2</a>", $message);
于 2013-10-30T21:53:36.307 回答
1

在我看来,解决这个问题是徒劳的。一个不错的选择是通过正则表达式(从协议开始:http、ftp、mail... 或 www)找到可能是 URL的内容,然后使用 FILTER_VALIDATE_URL 对其进行测试。请记住,此过滤器不是 PHP 手册中所说的防水方式:

"Note that the function will only find ASCII URLs to be valid; internationalized domain names (containing non-ASCII characters) will fail."

代码示例(未测试):

$message = preg_replace_callback(
    '~(?(DEFINE)
          (?<prot> (?>ht|f) tps?+ :// )         # you can add protocols here
      )
      (?>
          <a\b (?> [^<]++ | < (?!/a>) )++ </a>  # avoid links inside "a" tags
        |
          <[^>]++>                              # and tags attributes.
      ) (*SKIP)(?!)                             # makes fail the subpattern.
      |                                         # OR
      \b(?>(\g<prot>)|www\.)(\S++)              # something that begins with
                                                # "http://" or "www."
     ~xi',
    function ($match) {
        if (filter_var($match[2], FILTER_VALIDATE_URL)) {
            $url = (empty($match[1])) ? 'http://' : '';
            $url .= $match[0];
            return '<a href="away?to=' . $url . '"target="_blank">'
                 . $url . '</a>';
        } else { return $match[0] }
    },
    $message);
于 2013-10-30T23:14:56.383 回答