PHP了解回调 - preg_replace_callback()和preg_match_all()之间的区别

时间:2013-03-28 02:53:52

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

我对使用preg_replace_callback()

感到有点困惑

我有一个$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 
    }

我假设回调的工作方式是每个匹配都会调用回调(递归?)并返回结果,从而允许在$ content中使用已解析的{{1}即时替换URL中的URL来自$url

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

如果o99_simple_callbac()实际上传递了整个匹配数组,那么我之前使用过的(第一个例子中为preg_replace_callback())和回调示例之间究竟有什么区别?

我错过了什么/误会? 使用解析后的网址替换preg_match_all()中找到的URL的正确方法是什么?

3 个答案:

答案 0 :(得分:4)

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

假设我们在$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 with 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
        )

)

现在,每个子阵列包含每个匹配的捕获组,而不是匹配的集合,每个捕获组。 (换句话说,这是另一个数组的转置。)如果你想玩每场比赛的性别(或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使您有机会返回替换值。

答案 1 :(得分:3)

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

这就是你的回调应该是这样的:

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

上的手册示例

答案 2 :(得分:2)

preg_replace_callback

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