PHP Conference Japan 2024

preg_replace_callback_array

(PHP 7, PHP 8)

preg_replace_callback_array执行一个正则表达式搜索并且使用回调进行替换

说明

preg_replace_callback_array(
    array $pattern,
    string|array $subject,
    int $limit = -1,
    int &$count = null,
    int $flags = 0
): string|array|null

此函数的行为类似于 preg_replace_callback(),不同的是针对每个模式分别执行回调。

参数

pattern

一个关联数组,将模式(键)映射到callable(值)。

subject

要进行搜索和替换的字符串或字符串数组。

limit

每个模式在每个 subject 字符串中的最大可能替换次数。默认为 -1(无限制)。

count

如果指定,此变量将被填充为完成的替换次数。

flags

flags 可以是 PREG_OFFSET_CAPTUREPREG_UNMATCHED_AS_NULL 标志的组合,这两个标志会影响匹配数组的格式。有关更多详细信息,请参阅 preg_match() 中的描述。

返回值

如果 subject 参数是一个数组,preg_replace_callback_array() 返回一个数组,否则返回一个字符串。如果发生错误,返回值为 null

如果找到匹配项,将返回新的 subject,否则 subject 将保持不变。

错误/异常

如果传入的正则表达式模式无法编译为有效的正则表达式,则会发出 E_WARNING

更新日志

版本 说明
7.4.0 添加了 flags 参数。

示例

示例 #1 preg_replace_callback_array() 示例

<?php
$subject
= 'Aaaaaa Bbb';

preg_replace_callback_array(
[
'~[a]+~i' => function ($match) {
echo
strlen($match[0]), ' 个匹配 "a" 已找到', PHP_EOL;
},
'~[b]+~i' => function ($match) {
echo
strlen($match[0]), ' 个匹配 "b" 已找到', PHP_EOL;
}
],
$subject
);
?>

以上示例将输出

6 matches for "a" found
3 matches for "b" found

参见

添加注释

用户贡献的注释 4 条注释

up
10
Sz.
6 年前
根据一些测试,我发现了这个函数的这些重要特性。(这些
最好作为其规范的一部分进行记录,例如,为了确认。如果没有,
这只是实验性的好奇心。不过总比猜测好!;))

1. 更改会在回调之间级联到主题,即对主题进行的更改
回调将由下一个回调看到,如果其模式匹配
更改后的主题。
(但是 *相同* 回调的先前调用(在任何主题上)所做的更改
该回调将不再看到。)

2. 模式 + 回调对将按照它们出现的顺序应用
在 $patterns_and_callbacks 中。

3. 回调不能为 null(或 '')以快速替换为空。

4. 总的来说,算法开始迭代 $patterns_and_callbacks,然后
将每个 $subject 馈送到当前回调,对每个匹配重复
其在当前主题上的模式(与 "preg_match_all" 不同,后者
可以一次性完成,在数组中返回累积结果)。

这基本上意味着“皇冠上的明珠”,一个更有效的函数
"preg_replace_all_callback_array" 仍然缺少。

(当然,这更适合正则表达式 API 的新设计,其中一个
API 可以通过一些 $flags = [] 数组灵活地处理各种不同的模式。)

5. (最后一个并非特定于此函数,而是正则表达式固有的,另一方面,
它可能比 PHP 正则表达式支持中的任何其他地方都更相关。)

即使是看似简单的情况也会产生疯狂(且难以预测)
匹配数量,以及因此的回调调用,因此请记住设置
$limit,在可承受的情况下。但是,当然,首先尝试锐化你的模式!

例如使用 ^...$ 锚定以避免在匹配的子字符串上进行意外的额外调用
主题,(即 '/.*/',没有锚定,将匹配两次:一次匹配
整个主题,然后匹配尾随的空子字符串 - 但我不确定
这是否应该是正确的行为。)
up
9
drevilkuko at gmail dot com
8 年前
终于!!!

之前 (<=php5.6)

<?php
$htmlString
= preg_replace_callback(
'/(href="?)(\S+)("?)/i',
function (&
$matches) {
return
$matches[1] . urldecode($matches[2]) . $matches[3];
},
$htmlString
);

$htmlString = preg_replace_callback(
'/(href="?\S+)(%24)(\S+)?"?/i', // %24 = $
function (&$matches) {
return
urldecode($matches[1] . '$' . $matches[3]);
},
$htmlString
);
?>

php7

<?php

$htmlString
= preg_replace_callback_array(
[
'/(href="?)(\S+)("?)/i' => function (&$matches) {
return
$matches[1] . urldecode($matches[2]) . $matches[3];
},
'/(href="?\S+)(%24)(\S+)?"?/i' => function (&$matches) {
return
urldecode($matches[1] . '$' . $matches[3]);
}
],
$htmlString
);
?>
up
1
claus at tondering dot dk
6 个月前
请注意,第一个替换将应用于整个字符串,然后才会应用下一个替换。

例如

<?php
$subject
= 'a b a b a b';

preg_replace_callback_array(
[
'/a/' => function ($match) {
echo
'"a" found', PHP_EOL;
},
'/b/' => function ($match) {
echo
'"b" found', PHP_EOL;
}
],
$subject
);

?>

将打印

"a" found
"a" found
"a" found
"b" found
"b" found
"b" found

这意味着您不能使用全局变量在函数之间传递有关您在字符串中到达哪个点的信息。
up
-3
jfcherng at NOSPAM dot gmail dot com
8 年前
这是在旧版 PHP 中的一个可能的替代方案。

<?php

// if (!function_exists('preg_replace_callback_array')) {

function preg_replace_callback_array (array $patterns_and_callbacks, $subject, $limit=-1, &$count=NULL) {
$count = 0;
foreach (
$patterns_and_callbacks as $pattern => &$callback) {
$subject = preg_replace_callback($pattern, $callback, $subject, $limit, $partial_count);
$count += $partial_count;
}
return
preg_last_error() == PREG_NO_ERROR ? $subject : NULL;
}

// }

?>
To Top