简体   繁体   English

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

[英]PHP Understanding callbacks - difference between preg_replace_callback() and preg_match_all()

I am a bit confused on the use of preg_replace_callback() 我对preg_replace_callback()的使用有点困惑

I have a $content with some URLs inside . 我有一些$content包含一些URL的$content

Previously I used 以前我用过

 $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;

But what I really need is to REPLACE the original URL with my parsed URL... 但我真正需要的是用我解析的URL替换原始URL ...

So I tried the preg_replace_callback: 所以我尝试了preg_replace_callback:

function o99_simple_parse($content){

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


return $content;
}

and : 并且:

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 
    }

I assumed that the callback will work in a way that EVERY match will call the callback (recursively ?) and get back results , thus allowing for to replace on-the-fly the URLS in $content with the parsed $url from o99_simple_callbac() . 我假设回调将以一种方式工作,即每个匹配都会调用回调(递归?)并获得结果,从而允许在$ content中使用来自o99_simple_callbac()的解析后的$url进行o99_simple_callbac()

But another question here (and especially this comment ) triggered my doubts . 但是这里的另一个问题 (尤其是这个评论 )引发了我的怀疑。

If the preg_replace_callback() actually pass the whole array of matches , then what is actually the difference between what I used previously ( preg_match_all() in first example ) and the callback example ? 如果preg_replace_callback()实际传递了整个匹配数组,那么我之前使用过的(第一个例子中的preg_match_all() )和回调示例之间究竟有什么区别?

What am I missing / misunderstanding ?? 我错过了什么/误会? What would be the correct way of replacing the URLS found in $content with the parsed urls ? 用解析的URL替换$content找到的URL的正确方法是什么?

The other answers may have been sufficient, but let me give you one more take using a simpler example. 其他答案可能已经足够了,但让我再用一个更简单的例子再给你一个答案。

Let's say we have the following data in $subject , 假设我们在$subject有以下数据,

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

and the following regular expression in $pattern , $pattern的以下正则表达式,

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

Let's compare three approaches. 让我们比较三种方法。

preg_match_all preg_match_all

First, the vanilla preg_match_all : 首先,香草preg_match_all

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

Here's what $matches comes out to be: 以下是$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
        )

)

Whether we're talking about the gender field in my example with the URL field in your example, it's clear that looping through $matches[1] iterates through just that field: 无论我们是在谈论我跟在你的榜样URL字段例如性别领域,很明显,通过循环$matches[1]通过刚刚那场迭代:

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

However, as you noticed, changes you make to $matches[1] , even if you iterated through its subarrays by reference, do not reflect in $subject , ie you cannot perform replacements via preg_match_all . 但是,正如您所注意到的,您对$matches[1]所做的更改,即使您通过引用迭代其子数组,也不会反映在$subject您无法通过preg_match_all执行替换。

preg_match_all with PREG_SET_ORDER 使用PREG_SET_ORDER进行preg_match_all

Before we jump into preg_replace_callback though, let's take a look at one of preg_match_all 's commonly used flags, PREG_SET_ORDER . 在我们跳转到preg_replace_callback之前,让我们看一下preg_match_all的常用标志之一PREG_SET_ORDER

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

This outputs something (seemingly) completely different! 这输出(看似)完全不同的东西!

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
        )

)

Now, each subarray contains the set of capture groups per match , as opposed to the set of matches , per capture group . 现在,每个子阵列包含每个匹配的捕获组集合 ,而不是每个捕获组匹配集合。 (In yet other words, this is the transpose of the other array.) If you wanted to play with the gender (or URL) of each match, you'd now have to write this: (换句话说,这是另一个数组的转置。)如果你想玩每个匹配的性别(或URL),你现在必须写这个:

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

preg_replace_callback preg_replace_callback

And that's what preg_replace_callback is like. 这就是preg_replace_callback的样子。 It calls the callback for each set of matches (that is, including all its capture groups , at once), as if you were using the PREG_SET_ORDER flag. 它为每组匹配调用回调(即,同时包括其所有捕获组 ),就像使用PREG_SET_ORDER标志一样。 That is, contrast the way preg_replace_callback is used, 也就是说,与使用preg_replace_callback的方式形成鲜明对比,

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

to the PREG_SET_ORDER example. PREG_SET_ORDER示例。 Note how the two examples iterate through matches in exactly the same way, the only difference being that preg_replace_callback gives you an opportunity to return a value for replacement. 注意两个示例如何以完全相同的方式迭代匹配,唯一的区别是preg_replace_callback使您有机会返回替换值。

It does not pass all matches, but invokes the callback for each match. 它不会传递所有匹配项,但会为每个匹配项调用回调函数。 The callback won't receive a single string parameter, but a list of strings. 回调函数不会收到单个字符串参数,而是收到字符串列表。 $match[0] is the whole match, and $match[1] the first capture group (what's in your regex between the first parens). $match[0]是整个匹配, $match[1]是第一个捕获组(第一个parens之间的正则表达式中有什么)。

So this is how your callback should look: 所以这就是你的回调应该是这样的:

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 
}

Please also see the manual examples on preg_replace_callback 另请参阅preg_replace_callback上的手册示例

preg_replace_callback preg_replace_callback

  1. Using preg_replace_callback() to Replace Patterns 使用preg_replace_callback()替换模式
  2. Generating replacement strings with a callback function 使用回调函数生成替换字符串
  3. Generating replacement strings with an anonymous function 使用匿名函数生成替换字符串

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM