2009-09-20 14 views
11

私は.. PHPでアクセント文字の交換を行うが、私はUTF-8文字列を使用していますし、str_replaceが正しくマルチバイト文字列を扱うことができないので、私の推測がされてファンキーな結果を取得しようとしているPHPマルチバイトstr_replace?

$accents_search  = array('á','à','â','ã','ª','ä','å','Á','À','Â','Ã','Ä','é','è', 
'ê','ë','É','È','Ê','Ë','í','ì','î','ï','Í','Ì','Î','Ï','œ','ò','ó','ô','õ','º','ø', 
'Ø','Ó','Ò','Ô','Õ','ú','ù','û','Ú','Ù','Û','ç','Ç','Ñ','ñ'); 

$accents_replace = array('a','a','a','a','a','a','a','A','A','A','A','A','e','e', 
'e','e','E','E','E','E','i','i','i','i','I','I','I','I','oe','o','o','o','o','o','o', 
'O','O','O','O','O','u','u','u','U','U','U','c','C','N','n'); 

$str = str_replace($accents_search, $accents_replace, $str); 
私が手

結果:

Ørjan Nilsen -> �orjan Nilsen 

期待される結果:

Ørjan Nilsen -> Orjan Nilsen 

編集:私はUTF-8に設定私の内部文字ハンドラを持っている(mb_internaに従ってl_encoding())でも、$ strの値はUTF-8なので、私が知る限り、関係するすべての文字列はUTF-8です。 str_replace()は文字セットを検出して正しく使用していますか?

+0

ここで私の答えを確認してください:[PHPの文字を修正](http://stackoverflow.com/a/9499771/318380)。これは私の多くを助けた!!! – jazkat

答えて

5

入力エンコードとファイルエンコードの不一致が原因で文字列が置き換えられないように見えます。

+0

Aye、テキストファイルへのcliで実行されるUTF-8ファイル(iso端末への出力はありません)が動作します。 – OIS

+0

入力エンコーディングを変更するにはどうしたらいいですか? – Ian

+0

テキストエディタを確認しましたが、そのファイルエンコーディングはUTF-8に設定されています。 – Ian

2

は、この関数の定義を試してみてください。

if (!function_exists('mb_str_replace')) { 
    function mb_str_replace($search, $replace, $subject) { 
     if (is_array($subject)) { 
      foreach ($subject as $key => $val) { 
       $subject[$key] = mb_str_replace((string)$search, $replace, $subject[$key]); 
      } 
      return $subject; 
     } 
     $pattern = '/(?:'.implode('|', array_map(create_function('$match', 'return preg_quote($match[0], "/");'), (array)$search)).')/u'; 
     if (is_array($search)) { 
      if (is_array($replace)) { 
       $len = min(count($search), count($replace)); 
       $table = array_combine(array_slice($search, 0, $len), array_slice($replace, 0, $len)); 
       $f = create_function('$match', '$table = '.var_export($table, true).'; return array_key_exists($match[0], $table) ? $table[$match[0]] : $match[0];'); 
       $subject = preg_replace_callback($pattern, $f, $subject); 
       return $subject; 
      } 
     } 
     $subject = preg_replace($pattern, (string)$replace, $subject); 
     return $subject; 
    } 
} 
+0

多分私は間違っているかもしれませんが、正しいパターンは次のように見えます: '/( '。preg_quote(implode(' '、(array)$ search)、'/')。')/ u'' ?? – Igor

3

それはUnicode normalization form Dを使用して特殊記号(NFD)とUnicode文字プロパティを削除することが可能です。

NFDは、「ラテン小文字のU」(文字である)から「LATIN小文字U」(文字)および「COMBINING DIAERESIS」(文字ではない)に変換します。

header('Content-Type: text/plain; charset=utf-8'); 

$test = implode('', array('á','à','â','ã','ª','ä','å','Á','À','Â','Ã','Ä','é','è', 
'ê','ë','É','È','Ê','Ë','í','ì','î','ï','Í','Ì','Î','Ï','œ','ò','ó','ô','õ','º','ø', 
'Ø','Ó','Ò','Ô','Õ','ú','ù','û','Ú','Ù','Û','ç','Ç','Ñ','ñ')); 

$test = Normalizer::normalize($test, Normalizer::FORM_D); 

// Remove everything that's not a "letter" or a space (e.g. diacritics) 
// (see http://de2.php.net/manual/en/regexp.reference.unicode.php) 
$pattern = '/[^\pL ]/u'; 

echo preg_replace($pattern, '', $test); 

出力:

aaaaªaaAAAAAeeeeEEEEiiiiIIIIœooooºøØOOOOuuuUUUcCNn 

ノーマクラスはPECL intl packageの一部です。 (アルゴリズムそのものはあまり複雑ではありませんが、多くの文字マッピングをロードする必要があります)私はPHP implementationを書きました。

私はこれが素晴らしいテクニックだと思っています。

+0

本当に便利です。私は実際にアクセントを失う結果となるため、この例では使用したくないですが。 – Ian

+3

アクセントを取り除くことは、あなたがやろうとしていたものだと思いましたか? – mermshaus

16

phpの文書によると、str_replace関数はバイナリセーフです。つまり、データ損失なしでUTF-8エンコードされたテキストを処理できることを意味します。

+0

ありがとう、dav。 mb_substr()とmb_strlen()は存在するが、mb_str_replace()は存在しない理由を説明しているので、正解でなければなりません。最初の2つの関数は、str_replace()が使用されていない間にテキスト文字(テキストのエンコーディングに依存します)のオフセット位置を使用(または返す)します。そのため、str_replace()はUTF-8データを安全に(または他のUnicodeエンコーディングまたは一般にバイナリデータで)動作させることができます。 – StanE