【问题标题】:How to fix this preg_replace codes?如何修复这个 preg_replace 代码?
【发布时间】:2013-10-30 20:52:03
【问题描述】:

使用以下代码将邮件中的 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

示例:&lt;a href="http://www"&gt;www&lt;/a&gt;

那么问题是是否有任何方法可以解决上述代码中的这两种情况?

【问题讨论】:

  • 你永远找不到匹配所有 url 的正则表达式,并且只匹配 url。有太多不同的选择。话虽如此,在网上寻找一个好的可能会更快。
  • @hek2mgl:不,不需要完整的其他功能,只需修复上面的代码即可。
  • @Chevi:我不是想找到一个匹配所有 url 的正则表达式,但我确信上面的代码可以很容易地扩展到这两种情况。

标签: php url preg-replace


【解决方案1】:

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

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

这有帮助吗?

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

  • $
  • _
  • 。 (点)
  • +
  • !
  • *
  • '
  • (
  • )

如果要包含这些字符,则应使用 % 分隔正则表达式。

【讨论】:

  • 你的回答和很好的解释得到了我的支持,你所写和工作的一切都是正确的,但是我的问题只是回答了一半(缺少第二种情况)并且不包括 % 是不可能,因为维基百科在外语中大量使用%,还有很多网站使用%20 作为URL 中的空格。无论如何,非常感谢您的解释,它将帮助很多人了解它是如何工作的。
【解决方案2】:

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

$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);

【讨论】:

  • 即使我喜欢 Matewka 的答案的解释也是正确的,我会将您的答案标记为正确的解决方案,因为它是我问题中两种情况的有效答案。谢谢。
【解决方案3】:

在我看来,解决这个问题是徒劳的。一个不错的选择是通过正则表达式(从协议开始: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);

【讨论】:

    猜你喜欢
    • 2011-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    相关资源
    最近更新 更多