【问题标题】:Update function to recognize links [duplicate]更新功能以识别链接[重复]
【发布时间】:2019-12-21 14:39:18
【问题描述】:

我有这个功能来识别和转换主题标签、表情符号等

function convert_text($str) {
        $regex = "/[@#](\w+)/";
    //type and links
        $hrefs = [
            '#' => 'hashtag.php?hashtag',
            '@' => 'user.php?user'
        ];

        $result = preg_replace_callback($regex, function($matches) use ($hrefs) {
             return sprintf(
                 '<a href="%s=%s">%s</a>',
                 $hrefs[$matches[0][0]],
                 $matches[1], 
                 $matches[0]
             );
        }, $str);

        //$result = preg_replace("/U\+([A-F0-9]{5})/", '\u{${1}}', $result);
        $result = preg_replace('/U\+([A-F0-9]{5})/', '<span style="font-size:30px;">&#x\\1;</span>', $result);

        return ($result);
    }

我想让它从文本中识别http://https://,然后转换为:

&lt;a href="http://link.com"&gt;http://link.com&lt;/a&gt; 如何在函数内部实现呢?

【问题讨论】:

  • 转换表情符号有什么意义?他们已经是人物了。
  • 该功能已经识别和转换表情符号,我想让它重新转换和转换链接httphttps
  • 我在研究这个问题时看到了那个页面。它做了一件必需的事情,但该技术需要正确集成到 OP 的现有脚本中,以提供 OP 所需的结果。

标签: php regex


【解决方案1】:

我的猜测是,也许你可能想写一些接近于的表达式,

\bhttps?:\/\/\S*\b

Demo

匹配

$re = '/\bhttps?:\/\/\S*\b/s';
$str = 'some text before http://some_domain.com/some_link some text before  https://www.some_domain.com/some_link some text after';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

var_dump($matches);

输出

array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(32) "http://some_domain.com/some_link"
  }
  [1]=>
  array(1) {
    [0]=>
    string(37) "https://www.some_domain.com/some_link"
  }
}

替换

$re = '/(\bhttps?:\/\/\S*\b)/s';
$str = 'some text before http://some_domain.com/some_link some text before  https://www.some_domain.com/some_link some text after';
$subst = '<a href="$1">$1</a>';

echo preg_replace($re, $subst, $str);

输出

some text before <a href="http://some_domain.com/some_link">http://some_domain.com/some_link</a> some text before  <a href="https://www.some_domain.com/some_link">https://www.some_domain.com/some_link</a> some text after

如果您想探索/简化/修改表达式,它已经 在右上角的面板上进行了解释 regex101.com。如果你愿意,你 也可以在this link看,怎么搭配 针对一些样本输入。


正则表达式电路

jex.im 可视化正则表达式:

【讨论】:

  • 你将如何在我的函数中实现它?
  • 简洁美观。我想,一个问题可能是这对后跟标点符号的 URL 产生了意想不到的后果,因为标点符号将被视为 URL 的一部分。
【解决方案2】:

@tarleb 不,@emma 的这个正则表达式不会匹配那个标点符号,实际上不会匹配任何与 URL 末尾的 [a-zA-Z0-9_] 不同的东西。

RFC“合法”字符是[%A-Za-z0-9\-_~:\/?#\]\[@!$&amp;'()*+,;=]

因此,该正则表达式不会匹配以%.-_~:/?#][@!$&amp;'()*+,;= 结尾的有效网址,也不会匹配有效网址。因此,如果您想匹配它们而不是任何以 . 结尾的 URL,您应该添加:

(\bhttps?:\/\/\S{4,}(?:[-_~:\/?#\]\[@!$&amp;'()*+,;=%]|\b))

您也可以删除, 或任何其他您喜欢的匹配项。

function convert_text($str) {
    $regex = "/[@#](\w+)/";
//type and links
    $hrefs = [
        '#' => 'hashtag.php?hashtag',
        '@' => 'user.php?user'
    ];

    $result = preg_replace_callback($regex, function($matches) use ($hrefs) {
         return sprintf(
             '<a href="%s=%s">%s</a>',
             $hrefs[$matches[0][0]],
             $matches[1], 
             $matches[0]
         );
    }, $str);

    $result = preg_replace('/(\bhttps?:\/\/\S{4,}(?:[-_~:\/?#\]\[@!$&\'()*+,;=%]|\b))/', '<a href="\1">\1</a>', $result);

    //$result = preg_replace("/U\+([A-F0-9]{5})/", '\u{${1}}', $result);
    $result = preg_replace('/U\+([A-F0-9]{5})/', '<span style="font-size:30px;">&#x\\1;</span>', $result);

    return ($result);
}

Demo

【讨论】:

  • 你能在函数里做一个实现吗?
  • 你认为我会因为在函数中使用 $result 2 次而产生var 冲突吗?
  • 不,完全没问题
  • 此解决方案可能容易受到 JavaScript 代码注入的影响
【解决方案3】:

要识别链接,我会尝试:

function convert_text($str){
   return preg_replace_callback('/\bhttps?:\/\/[A-Z0-9+&@#\/%?=~_|$!:,.;-]*[A-Z0-9+&@#\/%=~_|$]/i', 'compute_replacement', $str);
}

function compute_replacement($groups) {
    return '<a href="$0">$0</a>';
}

【讨论】:

    【解决方案4】:

    我不会陷入关于构建一个征服世界的正则表达式模式来提取世界可以梦想的所有有效 url 的兔子洞,包括 unicode,同时拒绝具有有效字符但不合逻辑结构的 url。 (我会选择Gumbo 继续前进。)

    有关正则表达式演示,请参阅:https://regex101.com/r/HFCP1Z/1/

    注意事项:

    • 如果 url 匹配,则没有捕获组,因此不会生成 $m[1]。如果匹配用户/哈希标记,则会生成完整字符串匹配和捕获组 1。如果匹配表情符号,则填充完整字符串匹配,捕获组 1 元素为空(但声明是因为 php 生成 $m 作为索引数组 - 没有间隙),捕获组 2 保存表情符号的括号子字符串。

    • 需要确保不会意外替换包含合格主题标签/用户标签子字符串的部分网址。 (目前,其他答案不考虑此漏洞。)我将通过对输入执行单次传递并在其他模式有机会之前使用 whole url 子字符串来防止这种情况.
      (注意:http://example.com/@davehttp://example.com?asdf=1234#anchor

    • 我将您的主题标签/用户标签查找数组声明为常量有两个原因。

      1. 它没有变化,所以它不必是一个变量。
      2. 它享有全局范围,因此use() 语法在preg_replace_callback() 内不是必需的。
    • 您应该避免在标签中添加内联样式。我建议分配一个类,以便您在以后决定修改/扩展样式时可以简单地更新样式表的单个部分。

    代码:(Demo)

    define('PINGTAGS', [
            '#' => 'hashtag.php?hashtag',
            '@' => 'user.php?user'
        ]);
    
    function convert_text($str) {
        return preg_replace_callback(
            "~(?i)\bhttps?[-\w.\~:/?#[\]@!$&'()*+,;=]+|[@#](\w+)|U\+([A-F\d]{5})~",
            function($m) {
                // var_export($m);  // see for yourself
                if (!isset($m[1])) { // url
                    return sprintf('<a href="%s">%s</a>', $m[0], $m[0]);
                }
                if (!isset($m[2])) { // pingtag
                    return sprintf('<a href="%s=%s">%s</a>', PINGTAGS[$m[0][0]], $m[1], $m[0]);
                }
                return "<span class=\"emoji\">&#x{$m[2]};</span>"; // emoji
            },
            $str);
    }
    
    echo convert_text(
    <<<STRING
    This is a @ping and a #hash.
    This is a www.example.com, this is http://example.com?asdf=1234#anchor
    https://www.example.net/a/b/c/?g=5&awesome=foobar# U+23232 http://www5.example.com
    https://sub.sub.www.example.org/ @pong@pug#tagged
    http://example.com/@dave
    more http://example.com/more_(than)_one_(parens)
    andU+98765more http://example.com/blah_(wikipedia)#cite-1
    and more http://example.com/blah_(wikipedia)_blah#cite-1
    and more http://example.com/(something)?after=parens
    STRING
    );
    

    原始输出:

    This is a <a href="user.php?user=ping">@ping</a> and a <a href="hashtag.php?hashtag=hash">#hash</a>.
    This is a www.example.com, this is <a href="http://example.com?asdf=1234#anchor">http://example.com?asdf=1234#anchor</a>
    <a href="https://www.example.net/a/b/c/?g=5&awesome=foobar#">https://www.example.net/a/b/c/?g=5&awesome=foobar#</a> <span class="emoji">&#x23232;</span> <a href="http://www5.example.com">http://www5.example.com</a>
    <a href="https://sub.sub.www.example.org/">https://sub.sub.www.example.org/</a> <a href="user.php?user=pong">@pong</a><a href="user.php?user=pug">@pug</a><a href="hashtag.php?hashtag=tagged">#tagged</a>
    <a href="http://example.com/@dave">http://example.com/@dave</a>
    more <a href="http://example.com/more_(than)_one_(parens)">http://example.com/more_(than)_one_(parens)</a>
    and<span class="emoji">&#x98765;</span>more <a href="http://example.com/blah_(wikipedia)#cite-1">http://example.com/blah_(wikipedia)#cite-1</a>
    and more <a href="http://example.com/blah_(wikipedia)_blah#cite-1">http://example.com/blah_(wikipedia)_blah#cite-1</a>
    and more <a href="http://example.com/(something)?after=parens">http://example.com/(something)?after=parens</a>
    

    Stackoverflow 渲染输出:

    这是一个@ping 和一个#hash。 这是一个 www.example.com,这是http://example.com?asdf=1234#anchor https://www.example.net/a/b/c/?g=5&awesome=foobar#?http://www5.example.com https://sub.sub.www.example.org/@pong@pug#tagged http://example.com/@dave 更多http://example.com/more_(than)one(parens) 还有就是http://example.com/blah_(wikipedia)#cite-1 还有更多http://example.com/blah_(wikipedia)_blah#cite-1 还有更多http://example.com/(something)?after=parens

    附言此处未突出显示哈希和用户标签,但它们是您要求的本地链接。

    【讨论】:

    • 如果您稍后决定添加填充或其他样式声明,则类将不会继续膨胀您的 html 标记。一个简单的class 声明可让您的内容保持干净且易于管理。还有更多的原因。阅读以下内容:stackoverflow.com/q/2612483/2943403
    • 我应该等着看是否会有更好的答案。
    【解决方案5】:

    我的正则表达式不是为了验证一个 URL,而是为了识别一个 URL,假设 URL 是一个有效的。我们不要忘记,有效的 URL 可以同时包含查询字符串 主题标签。后者提出了一个问题,因为当前的convert_text 函数在假设它们不是 URL 的一部分的情况下查找主题标签。因此,我的正则表达式还将假定 URL 将 包含主题标签。因此,我在现有函数中添加了对preg_replace 的额外调用,如下所示:

    function convert_text($str) {
            $regex = "/[@#](\w+)/";
        //type and links
            $hrefs = [
                '#' => 'hashtag.php?hashtag',
                '@' => 'user.php?user'
            ];
    
            $result = preg_replace_callback($regex, function($matches) use ($hrefs) {
                 return sprintf(
                     '<a href="%s=%s">%s</a>',
                     $hrefs[$matches[0][0]],
                     $matches[1],
                     $matches[0]
                 );
            }, $str);
    
            //$result = preg_replace("/U\+([A-F0-9]{5})/", '\u{${1}}', $result);
            $result = preg_replace('/U\+([A-F0-9]{5})/', '<span style="font-size:30px;">&#x\\1;</span>', $result);
    
            // the addition:
            $result = preg_replace("~\bhttps?:/(/[^/\s]+)+/?(\?[^=\s]+=[^&\s]+(&(amp;)?[^=\s]+=[^&\s]+)*)?\b~", '<a href="$0">$0</a>', $result);
    
            return ($result);
    }
    

    测试:

    echo convert_text('#abc http://example.com https://example.com/a/b?x=1&y=2');
    

    打印:

    <a href="hashtag.php?hashtag=abc">#abc</a> <a href="http://example.com">http://example.com</a> <a href="https://example.com/a/b?x=1&y=2">https://examle.com/a/b?x=1&y=2</a>
    

    【讨论】:

    • 酷,我马上去测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 2016-09-29
    • 1970-01-01
    相关资源
    最近更新 更多