如何使用 strtr() 函数翻译多字节/带重音符号/变音符号的字符?

16
жңүжІЎжңүдәәжңүstrtr()еҮҪж•°зҡ„еӨҡеӯ—иҠӮеҸҳдҪ“пјҹ жңҹжңӣдҪҝз”Ёзҡ„зӨәдҫӢпјҡ
зӨәдҫӢпјҡ $from = 'ДҫДҫЕЎДҚЕҘЕҫГҪГЎГӯЕ•ДҸЕҲГӨГҙ'; // иҝҷдәӣеӯ—з¬ҰжҳҜ UTF-8 зј–з Ғзҡ„ $to = 'llsctzyairdnao';
// иҫ“е…Ҙ - дҪҝз”Ё UTF-8 зј–з Ғ $str = 'KЕ•deДҫ ДҸatДҫov uДҚГӯ koЕҲa ЕҫraЕҘ kГҙru.'; $str = mb_strtr( $str, $from, $to );
// иҫ“еҮә - жІЎжңүеҸҳйҹіз¬ҰеҸ·зҡ„еӯ—з¬ҰдёІ // $str = 'Krdel datlov uci kona zrat koru.'гҖӮ

我手头没有确切的例子,但是查看php文档页面上的用户评论总是值得的:http://us3.php.net/strtr 看起来有些人已经遇到了同样的问题。也许其中一个人已经在那里发布了解决方案。 - Max
4个回答

28

我认为 strtr 是多字节安全的,无论如何由于 str_replace 也是多字节安全的,因此您可以将其包装:

function mb_strtr($str, $from, $to)
{
  return str_replace(mb_str_split($from), mb_str_split($to), $str);
}

由于没有mb_str_split函数,您需要编写自己的函数(使用mb_substrmb_strlen),或者您可以使用稍作修改的PHP UTF-8实现:

function mb_str_split($str) {
    return preg_split('~~u', $str, null, PREG_SPLIT_NO_EMPTY);;

}

然而,如果您正在寻找一种从字符串中删除所有(拉丁语?)重音符号的函数,则可能会发现以下函数很有用:
function Unaccent($string)
{
    return preg_replace('~&([a-z]{1,2})(?:acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml|caron);~i', '$1', htmlentities($string, ENT_QUOTES, 'UTF-8'));
}

echo Unaccent('ľľščťžýáíŕďňä'); // llsctzyairdna
echo Unaccent('Iñtërnâtiônàlizætiøn'); // Internationalizaetion

1
@Alix Axel:你是正确的。我查看了strtr的文档:“如果from和to的长度不同,则较长的那个字符串中多余的字符将被忽略。返回值的长度将与str的长度相同。” - BertR
1
一个小改进:在正则表达式中添加 "caron",像这样:... slash|th|tilde|uml|caron); ...。现在像 'Škoda' 这样的文本也将被去重音符号化。 - liviucmg
1
@bilygates:我去检查了一下PHP是否支持“caron”变音符号,但它仍然没有出现在我的get_html_translation_table(HTML_ENTITIES)调用中。你使用的是哪个版本的PHP?你能在那个查找表中看到&...caron;实体吗?如果没有,htmlentities()就不应该对这些变音符号进行编码,这使得额外的正则表达式查找/替换无用。 - Alix Axel
1
@Alix Axel:使用get_html_translation_table(HTML_ENTITIES,ENT_QUOTES,'UTF-8')并将编码参数设置为UTF-8,您将看到Šš。我正在使用PHP 5.3.12。干杯! - liviucmg
1
@bilygates:没错,那一定是原因了。我正在使用PHP 5.3.2版本,而编码参数仅在PHP 5.3.4中添加。感谢您的回复。 - Alix Axel
显示剩余4条评论

2
function mb_strtr($str,$map,$enc){
$out="";
$strLn=mb_strlen($str,$enc);
$maxKeyLn=1;
foreach($map as $key=>$val){
    $keyLn=mb_strlen($key,$enc);
    if($keyLn>$maxKeyLn){
        $maxKeyLn=$keyLn;
    }
}
for($offset=0; $offset<$strLn; ){
    for($ln=$maxKeyLn; $ln>=1; $ln--){
        $cmp=mb_substr($str,$offset,$ln,$enc);
        if(isset($map[$cmp])){
            $out.=$map[$cmp];
            $offset+=$ln;
            continue 2;
        }
    }
    $out.=mb_substr($str,$offset,1,$enc);
    $offset++;
}
return $out;
}

1

可能使用 str_replace 是一个好的解决方案。另一种选择:

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

function my_strtr($inputStr, $from, $to, $encoding = 'UTF-8') {
        $inputStrLength = mb_strlen($inputStr, $encoding);

        $translated = '';

        for($i = 0; $i < $inputStrLength; $i++) {
                $currentChar = mb_substr($inputStr, $i, 1, $encoding);

                $translatedCharPos = mb_strpos($from, $currentChar, 0, $encoding);

                if($translatedCharPos === false) {
                        $translated .= $currentChar;
                }
                else {
                        $translated .= mb_substr($to, $translatedCharPos, 1, $encoding);
                }
        }

        return $translated;
}


$from = 'ľľščťžýáíŕďňä'; // these chars are in UTF-8
$to   = 'llsctzyairdna';

// input - in UTF-8
$str  = 'Kŕdeľ ďatľov učí koňa žrať kôru.';

print 'Original: ';
print chr(10);
print $str;

print chr(10);
print chr(10);

print 'Tranlated: ';
print chr(10);
print my_strtr( $str, $from, $to);

在我的机器上使用 PHP 5.2 打印:

Original: 
Kŕdeľ ďatľov učí koňa žrať kôru.

Tranlated: 
Krdel datlov uci kona zrat kôru.

0

strtr()有两个有效的签名来接收其参数。

您实现strtr()的方式执行逐字节翻译--这显然不适用于您的多字节字符。

$from = 'ľľščťžýáíŕďňäô'; // these chars are in UTF-8
$to   = 'llsctzyairdnao';

$str  = 'Kŕdeľ ďatľov učí koňa žrať kôru.';
echo strtr($str, $from, $to);
// Kd�deyn y�atynov uyaa� kod�a dnradr ka�ru.

正确的实现方式是向函数提供一个关联数组以进行翻译 - 这是多字节安全的做法。(演示)

$trans = [
    'ľ' => 'l',
    'š' => 's',
    'č' => 'c',
    'ť' => 't',
    'ž' => 'z',
    'ý' => 'y',
    'á' => 'a',
    'í' => 'i',
    'ŕ' => 'r',
    'ď' => 'd',
    'ň' => 'n',
    'ä' => 'a',
    'ô' => 'o',
];
echo strtr($str, $trans);
// Krdel datlov uci kona zrat koru.

需要注意的是,已经开发了库和本地函数来处理这样的任务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接