2013-11-22 23 views
1

我使用preg_replace來匹配並用適當的字符替換不正確編碼的UTF-8字符。我創建了一個包含錯誤字符的「舊」數組,以及一個帶有替換項的相應「新」數組。下面是每個陣列的一個片段:preg_replace:如何在更換之前考慮整個陣列的模式?

$old = array(
    '/â€/', 
    '/’/', 
); 
$new = array(
    '†', 
    '’', 
); 

注意:如果你很好奇,爲什麼我這樣做,read more here

可能包含錯誤的數據樣本字符串可以爲:

The programmer’s becoming very frustrated

應該變成:

The programmer's becoming very frustrated

我使用這個功能:

$result = preg_replace($old, $new, $str);

但拍攝對象實際上成爲:

The programmer†™s becoming very frustrated

很顯然,PHP是做什麼的我稱之爲非貪婪匹配的主題(不正確的術語在這裏使用,我知道)。 preg_replace正在執行舊/新陣列中第一對的替換,而不考慮模式數組中是否存在更適合的不同模式。如果我顛倒替換對的順序,那麼它按預期工作。

我的問題是:有沒有一種方法可以讓preg_replace在執行替換之前考慮模式數組的所有元素,還是我唯一的重新排序數組的選項?

回答

2

我不認爲有這樣的任何選項。但是,您可以使用關聯數組來存儲替換項,並使用uasortstrlen對其進行排序,因此較大的匹配項將首先出現,並且不需要手動管理陣列順序。

然後你可以使用array_keysarray_values行事就像你分離$old$new陣列。

$replacements = array(
    '†' => '/â€/', 
    '’' => '/’/', 
); 

// sorts the replacements array by value string length keeping the indexes intact 
uasort($replacements, function($a, $b) { 
    return strlen($b) - strlen($a); 
}); 

$str = 'The programmer’s becoming very frustrated'; 
$result = preg_replace(array_values($replacements), array_keys($replacements), $str); 

編輯:作爲@CasimiretHippolyte指出的那樣,使用array_values不上在這種情況下preg_replace函數的第一個參數所需的。它只會從$replacements返回一個帶有數字索引的副本,但順序是一樣的。除非您需要與您的問題具有相同結構的陣列$old,否則不需要使用它。

+1

請注意,不需要'array_values()'函數。 –

+0

謝謝@CasimiretHippolyte,我編輯了答案。 :) –

1

訂購陣列$old$new以這樣的方式,最長的正則表達式成爲第一:

$old = array(
    '/’/', 
    '/â€/', 
); 
$new = array(
    '’', 
    '†', 
); 
$str = 'The programmer’s becoming very frustrated'; 
$result = preg_replace($old, $new, $str); 
echo $result,"\n"; 

輸出:

The programmer’s becoming very frustrated 
0

我不相信只有使用preg_replace纔有辦法做到這一點。但是,您可以事先輕鬆地對陣列進行排序:

$replacements = array_combine($old, $new); 
krsort($replacements); 
$result = preg_repalce(array_keys($replacements), array_values($replacements), $string);