【问题标题】:Best way to make links clickable in block of text [duplicate]在文本块中使链接可点击的最佳方法[重复]
【发布时间】:2011-07-17 12:06:05
【问题描述】:

我想要:

Here is link: http://google.com
And http://example.com inside.
And another one at the very end: http://test.net

变成:

Here is link: <a href="http://google.com">http://google.com</a>
And <a href="http://example.com">http://example.com</a> inside.
And another one at the very end: <a href="http://test.net">http://test.net</a>

似乎是一项微不足道的任务,但我找不到有效的 PHP 函数。你有什么想法吗?

function make_links_clickable($text){
    // ???
}

$text = 'Here is link: http://google.com
And http://example.com inside.
And another one at the very end: http://test.net';

echo make_links_clickable($text);

【问题讨论】:

    标签: php regex preg-replace


    【解决方案1】:

    使用这个(适用于 ftp、http、ftps 和 https 方案):

    function make_links_clickable($text){
        return preg_replace('!(((f|ht)tp(s)?://)[-a-zA-Zа-яА-Я()0-9@:%_+.~#?&;//=]+)!i', '<a href="$1">$1</a>', $text);
    }
    

    【讨论】:

    • 你放在正则表达式开头和结尾的!是什么?
    • 您的正则表达式中的非 ASCII 字符是什么? ('я' 和 'Я')?
    • @NeilHillman:包含它们是为了支持西里尔文域名(А 和 Я 都是西里尔文)More InfoWikipedia
    • 这不适用于不以 http:// 开头的链接。我建议添加一个寻找 www 的 str_replace。并添加 http://infront。然后我会为 double htt p 添加另一个 str_replace checkign: //htt p : // 用一个替换它
    • @Akarun 如果链接是这样的怎么办? (https://www.sample.com/request). 该函数将包含“)”和“.”最后看起来像这样&lt;a href="https://www.sample.com/request)."&gt;https://www.sample.com/request).&lt;/a&gt;
    【解决方案2】:

    试试这样的:

    function make_links_clickable($text)
    {
       return preg_replace ('/http:\/\/[^\s]+/i', "<a href=\"${0}\">${0}</a>", $text);
    } 
    
    $result = make_links_clickable($text);
    

    【讨论】:

    • Akarun 和 Lawrence Cherone 建议的链接中提供的解决方案更完整,因为他们检查 url 以获取有效 url,他们还检测 https 和 ftp 链接,他们在显示链接之前对链接进行 urldecode。我的解决方案更脏,但它应该适用于简单的任务。
    • 这个答案缺少教育解释。
    【解决方案3】:
    function makeClickableLinks($text)
    {
    $text = html_entity_decode($text);
    $text = " ".$text;
    $text= preg_replace("/(^|[\n ])([\w]*?)([\w]*?:\/\/[\w]+[^ \,\"\n\r\t<]*)/is", "$1$2<a href=\"$3\" >$3</a>", $text);  
    $text= preg_replace("/(^|[\n ])([\w]*?)((www|wap)\.[^ \,\"\t\n\r<]*)/is", "$1$2<a href=\"http://$3\" >$3</a>", $text);
    $text= preg_replace("/(^|[\n ])([\w]*?)((ftp)\.[^ \,\"\t\n\r<]*)/is", "$1$2<a href=\"$4://$3\" >$3</a>", $text);  
    $text= preg_replace("/(^|[\n ])([a-z0-9&\-_\.]+?)@([\w\-]+\.([\w\-\.]+)+)/i", "$1<a href=\"mailto:$2@$3\">$2@$3</a>", $text);  
    $text= preg_replace("/(^|[\n ])(mailto:[a-z0-9&\-_\.]+?)@([\w\-]+\.([\w\-\.]+)+)/i", "$1<a href=\"$2@$3\">$2@$3</a>", $text);  
    $text= preg_replace("/(^|[\n ])(skype:[^ \,\"\t\n\r<]*)/i", "$1<a href=\"$2\">$2</a>", $text);  
            return $text;
    }
    

    合作:

    www.example.com

    https://www.example.com

    http://www.example.com

    wap.example.com

    ftp.example.com

    user@example.com

    Skype:示例

    mailto:user@example.com

    另一个协议://example.com

    【讨论】:

    • 这些连续的替换浪潮无法解释。这个答案是不完整的,任何使用这个答案的人都可能是盲目的复制粘贴。这个答案应该被编辑为更加慷慨/有教育意义。应该只有一个preg_replace() 电话;应该有一个模式数组和一个替换数组。
    【解决方案4】:

    同样受到 Akarun 回答的启发,以下函数将只链接尚未成为链接的文本。添加的功能是检查目标字符串中是否不存在带有捕获的文本链接的链接:

    function make_links_from_http($content) {   
        // Links out of text links
        preg_match_all('!(((f|ht)tp(s)?://)[-a-zA-Zа-яА-Я()0-9@:%_+.~#?&;//=]+)!i', $content, $matches);
        foreach ($matches[0] as $key=>$link) {
            if (!preg_match('!<a(.*)'.$link.'(.*)/a>!i', $content))
            {
                $content = str_replace($link, '<a href="'.$link.'" target="_blank">'.$link.'</a>', $content);
            }
        }
    
        return $content;
    } 
    

    通过测试,我注意到上述函数在第 5 行失败。完成这项工作的“混乱”功能如下:

    function make_links_from_http($content) 
    {
        // The link list
        $links = array();
    
        // Links out of text links
        preg_match_all('!(((f|ht)tp(s)?://)[-a-zA-Zа-яА-Я()0-9@:%_+.~#?&;//=]+)!i', $content, $matches);
        foreach ($matches[0] as $key=>$link) 
        {
            $links[$link] = $link;
        }
    
        // Get existing
        preg_match_all('/<a\s[^>]*href=([\"\']??)([^\" >]*?)\\1[^>]*>(.*)<\/a>/siU', $content, $matches);
        foreach ($matches[2] as $key=>$value)
        {
            if (isset($links[$value]))
            {
                unset($links[$value]);
            }
        }
    
        // Replace in content
        foreach ($links as $key=>$link)
        {
            $content = str_replace($link, '<a href="'.$link.'" target="_blank">'.$link.'</a>', $content);
        }
    
        return $content;
    } 
    

    对于新代码,我使用了以下教程: http://www.the-art-of-web.com/php/parse-links/

    【讨论】:

    • 当您需要执行嵌套在preg_ 调用中的preg_ 调用时,这通常表明第一个正则表达式模式设计得不好。当您匹配匹配项只是为了迭代和替换匹配的内容时,这通常表明您应该使用preg_replace_callback()
    【解决方案5】:

    受 Akarun 回答的启发,我想出了 tis 函数来处理仅以 www. 开头的所有协议和链接

    function make_links($text, $class='', $target='_blank'){
        return preg_replace('!((http\:\/\/|ftp\:\/\/|https\:\/\/)|www\.)([-a-zA-Zа-яА-Я0-9\~\!\@\#\$\%\^\&\*\(\)_\-\=\+\\\/\?\.\:\;\'\,]*)?!ism', 
        '<a class="'.$class.'" href="//$3" target="'.$target.'">$1$3</a>', 
        $text);
    }
    

    这个函数有可选参数来添加类名到链接和链接的可选目标,所以它们在新窗口/选项卡上打开...默认情况下,参数打开到新窗口/选项卡的链接,但如果你觉得喜欢不这样做,您可以更改默认值,或者在调用函数时更改值。

    【讨论】:

    • 这种模式非常臃肿,在模式中存在不必要的转义。如果模式中没有.(任何字符“点”),请问自己为什么要使用s 模式修饰符。然后问问自己,如果模式中没有 ^$(锚点),为什么要使用 m 模式修饰符。 http\:\/\/|https\:\/\/ 不必要地冗长。 a-zA-Zа-яА-Я 过于冗长。我不建议任何人使用这个 sn-p——即使它提供了预期的结果,因为它没有教授最佳实践。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 2011-05-31
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 2022-07-28
    • 1970-01-01
    相关资源
    最近更新 更多