4

我一直在尝试遍历一个字符串并用链接查找和替换 URL,这是我到目前为止所提出的,它似乎在大多数情况下工作得很好,但是有一些我想要的东西抛光。此外,它可能不是最好的执行方式。

我已经在 SO 上阅读了很多关于此的主题,虽然它有很大帮助,但我仍然需要解决它的松散端。

我在字符串中运行了两次。我第一次用 html 标签替换 bbtags;第二次我遍历字符串并用链接替换文本网址:

$body_str = preg_replace('/\[url=(.+?)\](.+?)\[\/url\]/i', '<a href="\1" rel="nofollow" target="_blank">\2</a>', $body_str);

$body_str = preg_replace_callback(
    '!(?:^|[^"\'])(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?!',
    function ($matches) {
        return strpos(trim($matches[0]), 'thisone.com') == FALSE ?
        '<a href="' . ltrim($matches[0], " \t\n\r\0\x0B.,@?^=%&amp;:/~\+#'") . '" rel="nofollow" target="_blank">' . ltrim($matches[0], "\t\n\r\0\x0B.,@?^=%&amp;:/~\+#'") . '</a>' :
        '<a href="' . ltrim($matches[0], " \t\n\r\0\x0B.,@?^=%&amp;:/~\+#'") . '">' . ltrim($matches[0], "\t\n\r\0\x0B.,@?^=%&amp;:/~\+#'") . '</a>';
    },
    $body_str
);

到目前为止,我发现的几个问题是它倾向于在“http”等之前立即拾取字符,例如空格/逗号/冒号等,这会破坏链接。因此,我使用 preg_replace_callback 来解决这个问题并修剪一些会破坏链接的不需要的字符。

另一个问题是,为了避免通过匹配已经在 A 标记中的 url 来破坏链接,我目前正在排除以引号、双引号开头的 url,我宁愿使用 href='|href=" 进行排除。

任何提示和建议将不胜感激

4

1 回答 1

0

首先,我允许自己重构一些代码,使其更易于阅读和修改:

函数 urltrim($str) {
   返回 ltrim($str, " \t\n\r\0\x0B.,@?^=%&:/~\+#'");
}
函数 addlink($str,$nofollow=true) {
        返回 '​​<a href="' . urltrim($str) . '"'.($nofollow ? ' rel="nofollow" target="_blank"' : '').'>' 。urltrim($str) 。'</a>';
}
功能检查点($str){
        返回 strpos(trim($str), 'thisone.com') == FALSE ?addlink($str) : addlink($str,false);
}

$body_str = preg_replace('/\[url=(.+?)\](.+?)\[\/url\]/i', '\2', $body_str);

$body_str = preg_replace_callback(
    '!(?:^|[^"\'])(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\ -\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?!',
       功能($匹配){
        返回检查点($matches[0]);
    },

    $body_str
);

之后我改变了你处理链接的方式:

  • 我认为 URL 是一个单词(= 所有字符,直到找到空格或 \n 或 \t (=\s))
  • 我更改了匹配方法以匹配字符串前面 href= 的存在
    • 如果它存在那么我什么都不做,它已经是一个链接
    • 如果没有 href= 存在,那么我替换链接
  • 所以 urltrim 方法不再有用了,因为我没有吃掉 http 之前的第一个字符
  • 当然,我使用 urlencode 对 url 进行编码并避免 html 注入
函数 urltrim($str) {
    返回 $str;
}
函数 addlink($str,$nofollow=true) {
        $url = preg_replace("#(https?)%3A%2F%2F#","$1://",urlencode(urltrim($str)));
        返回 '​​<a href="' . $url . '"'.($nofollow ? ' rel="nofollow" target="_blank"' : '').'>' 。urltrim($str) 。'</a>';
}
功能检查点($str){
        返回 strpos(trim($str), 'thisone.com') == FALSE ?addlink($str) : addlink($str,false);
}

$body_str = preg_replace('/\[url=(.+?)\](.+?)\[\/url\]/i', '\2', $body_str);

$body_str = preg_replace_callback(
    '!(|href=)(["\']?)(https?://[^\s]+)!',
    功能($匹配){
        如果($matches[1]){
            # 如果 href= 存在,不做任何事情,返回原始字符串
            返回 $matches[0];
        } 别的 {
            # 添加前一个字符(“或')和链接
            返回 $matches[2].checksite($matches[3]);
        }
    },
    $body_str
);

我希望这对您的项目有所帮助。告诉我们是否有帮助。

再见。

于 2013-08-09T11:51:49.763 回答