3

我对使用有点困惑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 
    }

我假设回调将以每个匹配项都会调用回调(递归?)并返回 results 的方式工作,从而允许用解析$url的 from动态替换 $content 中的 URL o99_simple_callbac()

但是这里的另一个问题(尤其是这个评论)引发了我的怀疑。

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

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

4

3 回答 3

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 与 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
        )

)

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

于 2013-03-28T14:57:29.323 回答
3

它不会传递所有匹配项,但会为每个匹配项调用回调。回调不会接收单个字符串参数,而是字符串列表。$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

于 2013-03-28T03:03:05.497 回答
2

preg_replace_callback

  1. 使用 preg_replace_callback() 替换模式
  2. 使用回调函数生成替换字符串
  3. 使用匿名函数生成替换字符串
于 2013-03-28T03:00:15.070 回答