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]), ' 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

另請參閱

新增附註

使用者貢獻的附註 4 則附註

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(如果負擔得起)。當然,請嘗試先銳化您的模式!

例如,使用 ^...$ 定錨來避免在主題的比對子字串上產生非預期的額外呼叫
,(也就是說,沒有定錨的 '/.*/' 會比對兩次:一次針對
整個主題,然後針對尾隨的空子字串 -- 但我不確定
這是否應該是正確的行為。)
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
);
?>
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

這表示您無法使用全域變數在函數之間傳遞關於您在字串中已到達哪個點的資訊。
-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