preg_replace_callback_array
(PHP 7, PHP 8)
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_CAPTURE
とPREG_UNMATCHED_AS_NULL
の組み合わせが指定できます。 これは matches 配列のフォーマットに影響します。 詳細は preg_match() 関数の説明を参照ください。
戻り値
preg_replace_callback_array() は、
subject
が配列の場合には配列を、
それ以外の場合は文字列を返します。
エラー時の戻り値は 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]), ' matches for "a" found', PHP_EOL;
},
'~[b]+~i' => function ($match) {
echo strlen($match[0]), ' matches for "b" found', PHP_EOL;
}
],
$subject
);
?>
上の例の出力は以下となります。
6 matches for "a" found 3 matches for "b" found
参考
- PCRE のパターン
- preg_replace_callback() - 正規表現検索を行い、コールバック関数を使用して置換を行う
- preg_quote() - 正規表現文字をクオートする
- preg_replace() - 正規表現検索および置換を行う
- preg_last_error() - 直近の PCRE 正規表現処理のエラーコードを返す
- 無名関数
User Contributed Notes 4 notes
Based on some tests, I found these important traits of the function. (These would
be nice to see documented as part of its spec, e.g. for confirmation. Without that,
this is just experimental curiosity. Still better than guesswork, though! ;) )
1. Changes cascade over a subject across callbacks, i.e. a change made to a
subject by a callback will be seen by the next callback, if its pattern matches
the changed subject.
(But a change made by a previous call of the *same* callback (on any subject)
will not be seen by that callback again.)
2. The pattern + callback pairs will be applied in the order of their appearance
in $patterns_and_callbacks.
3. The callback can't be null (or '') for a quick shortcut for empty replacements.
4. Overall, the algorithm starts iterating over $patterns_and_callbacks, and then
feeds each $subject to the current callback, repeatedly for every single match
of its pattern on the current subject (unlike "preg_match_all", that is, which
can do the same in one go, returning the accumulated results in an array).
This basically means that the "crown jewel", an even more efficient function:
"preg_replace_all_callback_array" is still missing from the collection.
(Of course, that would better fit a new design of the regex API, where one
API could flexibly handle various different modes via some $flags = [] array.)
5. (This last one is not specific to this function, but inherent to regexes, OTOH,
it's probably more relevant here than anywhere else in PHP's regex support.)
Even apparently simple cases can generate a crazy (and difficult-to-predict)
number of matches, and therefore callback invokations, so remember the set
$limit, where affordable. But, of course, try to sharpen your patterns first!
E.g. use ^...$ anchoring to avoid unintended extra calls on matching substrings
of a subject, (I.e. '/.*/', without anchoring, would match twice: once for the
whole subject, and then for a trailing empty substring -- but I'm not quite sure
this should actually be correct behavior, though.)
finally!!!
before (<=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
);
?>
Note that the first replacement is applied to the whole string before the next replacement is applied.
For example:
<?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
);
?>
will print
"a" found
"a" found
"a" found
"b" found
"b" found
"b" found
This means that you cannot use global variables to communicate information between the functions about what point in the string you have reached.
Here's a possible alternative in older 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;
}
// }
?>