2009-09-20 101 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 

编辑:我有(按mb_interna我的内部字符处理程序中设置为UTF-8 l_encoding()),$ str的值也是UTF-8,所以我所知道的所有字符串都是UTF-8。 str_replace()是否会检测字符集并正确使用它们?

+0

检查我的答案在这里:在PHP修复字符(http://stackoverflow.com/a/9499771/318380)。这对我帮助很大! – jazkat 2012-02-29 14:12:19

回答

5

看起来是不会被替换的字符串,因为你的输入编码和文件编码不匹配。

+0

埃,上CLI到文本文件UTF-8文件运行(不输出到异终端)的工作原理。 – OIS 2009-09-20 14:52:54

+0

那么我怎样才能改变我的输入编码呢? – Ian 2009-09-20 14:58:49

+0

我检查了我的文本编辑器,它的文件编码设置为UTF-8。 – Ian 2009-09-20 15:56:16

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(破灭(“”,(阵列)$搜索),“/').')/ u''? – Igor 2011-06-14 14:05:29

3

这是可能的,除去使用Unicode normalization form D(NFD),变音符号和Unicode字符属性。

NFD将“拉丁小写字母U”(这是一封信)中的“ü”元音变换为“拉丁小写字母U”(字母)和“组合字母”(不是字母)。

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的一部分。 (算法本身不是很复杂,但需要加载很多字符映射afaik,前一段时间我写了一个PHP implementation

(我加了两个月,因为我认为这是一个很好的技术,不够广泛)

+0

谢谢,这实际上非常有用。虽然我不想在这种情况下使用它,因为它会导致重音的丢失。 – Ian 2009-11-20 16:10:49

+3

我认为摆脱口音是你想要做的? – mermshaus 2009-11-25 15:59:31

16

根据php文档str_replace函数是二进制安全的,这意味着它可以处理UTF-8编码的文本没有任何数据丢失。

+0

谢谢,dav。这应该是正确的答案,因为它解释了为什么有mb_substr()和mb_strlen(),但不mb_str_replace()。前两个函数使用(或返回)文本字符的偏移位置(取决于文本编码),而不使用str_replace()。这就是为什么str_replace()可以安全地使用UTF-8数据(或任何其他Unicode编码或通常使用二进制数据)的原因。 – StanE 2015-05-08 09:57:44