【问题标题】:PHP Understanding callbacks - difference between preg_replace_callback() and preg_match_all()PHP 理解回调 - preg_replace_callback() 和 preg_match_all() 之间的区别
【发布时间】:2013-03-28 02:53:51
【问题描述】:

我对@9​​87654323@的使用有点困惑

我有一个$content,里面有一些网址。

我以前用过

 $content = preg_match_all( '/(http[s]?:[^\s]*)/i', $content, $links );


 foreach ($links[1] as $link ) {
            // we have the link. find image , download, replace the content with image
            // echo '</br>LINK : '. $link;
            $url = esc_url_raw( $link );
            $url_name = parse_url($url); 
            $url_name = $description = $url_name['host'];// get rid of http://..
            $url = 'http://somescriptonsite/v1/' .  urlencode($url)   . '?w=' . $width ;
            } 

    return $url;

但我真正需要的是用我解析的 URL 替换原始 URL...

所以我尝试了 preg_replace_callback:

function o99_simple_parse($content){

$content = preg_replace_callback( '/(http[s]?:[^\s]*)/i', 'o99_simple_callback', $content );


return $content;
}

和:

function o99_simple_callback($url){
    // how to get the URL which is actually the match? and width ??
        $url = esc_url_raw( $link );
        $url_name = parse_url($url); 
        $url_name = $description = $url_name['host'];// get rid of http://..
        $url = 'http://something' .  urlencode($url)   . '?w=' . $width ; 
        return $url; // what i really need to replace 
    }

我假设回调将以这样一种方式工作,即每个匹配项都会调用回调(递归?)并返回结果,从而允许使用解析的 $url 即时替换 $content 中的 URL来自o99_simple_callbac()

但是这里的另一个question(尤其是this comment)引发了我的怀疑。

如果preg_replace_callback() 实际上传递了整个匹配数组,那么我之前使用的(第一个示例中的preg_match_all())与回调示例之间的实际区别是什么?

我错过了什么/误解了什么? 用解析后的 url 替换 $content 中的 URL 的正确方法是什么?

【问题讨论】:

    标签: php callback preg-match-all preg-replace-callback


    【解决方案1】:

    其他答案可能已经足够了,但让我再举一个更简单的例子。

    假设我们在$subject中有以下数据,

    RECORD Male 1987-11-29 New York
    RECORD Female 1987-07-13 Tennessee
    RECORD Female 1990-04-14 New York
    

    以及$pattern中的以下正则表达式,

    /RECORD (Male|Female) (\d\d\d\d)-(\d\d)-(\d\d) ([\w ]+)/
    

    让我们比较三种方法。

    preg_match_all

    首先,香草preg_match_all

    preg_match_all($pattern, $subject, $matches);
    

    $matches 的结果如下:

    Array
    (
        [0] => Array
            (
                [0] => RECORD Male 1987-11-29 New York
                [1] => RECORD Female 1987-07-13 Tennessee
                [2] => RECORD Female 1990-04-14 New York
            )
    
        [1] => Array
            (
                [0] => Male
                [1] => Female
                [2] => Female
            )
    
        [2] => Array
            (
                [0] => 1987
                [1] => 1987
                [2] => 1990
            )
    
        [3] => Array
            (
                [0] => 11
                [1] => 07
                [2] => 04
            )
    
        [4] => Array
            (
                [0] => 29
                [1] => 13
                [2] => 14
            )
    
        [5] => Array
            (
                [0] => New York
                [1] => Tennessee
                [2] => New York
            )
    
    )
    

    无论我们是在我的示例中讨论性别字段还是在您的示例中使用 URL 字段,很明显循环 $matches[1] 会迭代只是该字段:

    foreach ($matches[1] as $match)
    {
        $gender = $match;
        // ...
    }
    

    但是,正如您所注意到的,您对 $matches[1] 所做的更改,即使您通过引用迭代其子数组,不要反映在 $subject 中,您无法通过preg_match_all 执行替换。

    preg_match_all 与 PREG_SET_ORDER

    在我们进入preg_replace_callback 之前,让我们看一下preg_match_all 的常用标志之一PREG_SET_ORDER

    preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
    

    这会输出一些(看似)完全不同的东西!

    Array
    (
        [0] => Array
            (
                [0] => RECORD Male 1987-11-29 New York
                [1] => Male
                [2] => 1987
                [3] => 11
                [4] => 29
                [5] => New York
            )
    
        [1] => Array
            (
                [0] => RECORD Female 1987-07-13 Tennessee
                [1] => Female
                [2] => 1987
                [3] => 07
                [4] => 13
                [5] => Tennessee
            )
    
        [2] => Array
            (
                [0] => RECORD Female 1990-04-14 New York
                [1] => Female
                [2] => 1990
                [3] => 04
                [4] => 14
                [5] => New York
            )
    
    )
    

    现在,每个子数组包含 每个匹配 的捕获组 set,而不是每个 捕获的 匹配 组组。 (换句话说,这是另一个数组的转置。)如果你想使用每场比赛的性别(或 URL),你现在必须这样写:

    foreach ($matches as $match)
    {
        $gender = $match[1];
        // ...
    }
    

    preg_replace_callback

    这就是preg_replace_callback 的样子。它为每个匹配集(即一次包括所有它的捕获组)调用回调,就像您使用PREG_SET_ORDER 标志一样。也就是对比preg_replace_callback的使用方式,

    preg_replace_callback($pattern, $subject, 'my_callback');
    function my_callback($matches)
    {
        $gender = $match[1];
        // ...
        return $gender;
    }
    

    PREG_SET_ORDER 为例。请注意这两个示例如何以完全相同的方式遍历匹配项,唯一的区别是preg_replace_callback 让您有机会返回一个替换值。

    【讨论】:

    • 哇。这个答案是一个很好的解释。教/学永远不会太晚,唯一的事情是我之前已经接受了@mario 的答案.. 但是1000 感谢您花时间解释!
    • 完全没问题;没想到你不接受@mario 的回答;我只是想从另一个线程完成回答您的问题。编码愉快。
    【解决方案2】:

    它不会传递所有匹配项,但会为每个匹配项调用回调。回调不会接收单个字符串参数,而是字符串列表。 $match[0] 是整个匹配项,$match[1] 是第一个捕获组(第一个括号之间的正则表达式中的内容)。

    你的回调应该是这样的:

    function o99_simple_callback($match){
        $url = $match[1];
        //$url = esc_url_raw( $link );
        $url_name = parse_url($url); 
        $url_name = $description = $url_name['host'];// get rid of http://..
        $url = 'http://something' .  urlencode($url)   . '?w=' . $width ; 
        return $url; // what i really need to replace 
    }
    

    另请参阅preg_replace_callback 上的手册示例

    【讨论】:

    • 谢谢!澄清一点..我当然在询问之前阅读了手册,但不知何故我误解了比赛通过的方式。 (也许对于像我这样的新手来说,那里的例子太复杂了)现在我觉得它更清楚了。再次感谢。
    【解决方案3】:

    preg_replace_callback

    1. 使用 preg_replace_callback() 替换模式
    2. 使用回调函数生成替换字符串
    3. 使用匿名函数生成替换字符串

    【讨论】:

    • 谢谢,+1 虽然在 java (?) 页面上,这些都是很好的参考。
    猜你喜欢
    • 2010-09-26
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 2013-11-04
    • 2020-05-02
    • 1970-01-01
    • 2014-11-03
    • 2021-10-31
    相关资源
    最近更新 更多