如何将“\u00ed”等Unicode转义序列解码为正确的UTF-8编码字符?

How to decode Unicode escape sequences like "\u00ed" to proper UTF-8 encoded characters?

提问人:Docstero 提问时间:5/29/2010 最后编辑:CommunityDocstero 更新时间:6/30/2023 访问量:171246

问:

PHP中是否有可以解码Unicode转义序列(如“”到“)以及所有其他类似情况的函数?\u00edí

我在这里发现了类似的问题,但似乎不起作用。

php unicode utf-8 转义 解码

评论


答:

207赞 Gumbo 5/29/2010 #1

试试这个:

$str = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function ($match) {
    return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
}, $str);

如果是基于 UTF-16 的 C/C++/Java/Json 风格:

$str = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function ($match) {
    return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UTF-16BE');
}, $str);

评论

2赞 Gumbo 5/29/2010
@Docstero:正则表达式将匹配后跟四个十六进制数字的任何序列。\u
0赞 Docstero 5/29/2010
警告:preg_replace_callback() [function.preg-replace-callback]:编译失败:PCRE 不支持偏移量 1 处的 \L、\l、\N、\U 或 \u
9赞 Artefacto 11/18/2011
此函数无法处理补充字符,因为它们无法在 UCS-2 中表示。
4赞 Demodave 5/18/2015
@gumbo 如何调用或使用此函数?
3赞 Tom Andersen 9/26/2017
我在这里找到了自己的方式,因为我在我的输出中\u00ed,但我正在用json_encode()查看输出,有趣的是,默认的json_encode()会破坏输出,所以使用json_encode($theDict,JSON_PRETTY_PRINT |JSON_UNESCAPED_UNICODE);
83赞 2BJ 11/2/2011 #2
print_r(json_decode('{"t":"\u00ed"}')); // -> stdClass Object ( [t] => í )

评论

56赞 deceze 5/15/2013
它甚至不需要对象包装器:json_decode('"' . $text . '"')
5赞 T.Todua 11/25/2016
谢谢。这似乎是标准方式,而不是公认的答案。
1赞 DynamicDan 10/23/2017
有趣的是,这也适用于复杂的实体,如笑脸...... 是 😊json_decode('{"t":"\uD83D\uDE0A"}')
3赞 Yvan 10/24/2018
@deceze,您应该包括可以包含双引号的事实。因此,修订后的版本将是:.感谢您的帮助:-)$textjson_decode('"'.str_replace('"', '\\"', $text).'"')
1赞 Stavros 10/13/2022
评论胜过所有答案
1赞 jianyong 5/10/2014 #3

还有一个解决方案:
http://www.welefen.com/php-unicode-to-utf8.html

function entity2utf8onechar($unicode_c){
    $unicode_c_val = intval($unicode_c);
    $f=0x80; // 10000000
    $str = "";
    // U-00000000 - U-0000007F:   0xxxxxxx
    if($unicode_c_val <= 0x7F){         $str = chr($unicode_c_val);     }     //U-00000080 - U-000007FF:  110xxxxx 10xxxxxx
    else if($unicode_c_val >= 0x80 && $unicode_c_val <= 0x7FF){         $h=0xC0; // 11000000
        $c1 = $unicode_c_val >> 6 | $h;
        $c2 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2);
    } else if($unicode_c_val >= 0x800 && $unicode_c_val <= 0xFFFF){         $h=0xE0; // 11100000
        $c1 = $unicode_c_val >> 12 | $h;
        $c2 = (($unicode_c_val & 0xFC0) >> 6) | $f;
        $c3 = ($unicode_c_val & 0x3F) | $f;
        $str=chr($c1).chr($c2).chr($c3);
    }
    //U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    else if($unicode_c_val >= 0x10000 && $unicode_c_val <= 0x1FFFFF){         $h=0xF0; // 11110000
        $c1 = $unicode_c_val >> 18 | $h;
        $c2 = (($unicode_c_val & 0x3F000) >>12) | $f;
        $c3 = (($unicode_c_val & 0xFC0) >>6) | $f;
        $c4 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2).chr($c3).chr($c4);
    }
    //U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    else if($unicode_c_val >= 0x200000 && $unicode_c_val <= 0x3FFFFFF){         $h=0xF8; // 11111000
        $c1 = $unicode_c_val >> 24 | $h;
        $c2 = (($unicode_c_val & 0xFC0000)>>18) | $f;
        $c3 = (($unicode_c_val & 0x3F000) >>12) | $f;
        $c4 = (($unicode_c_val & 0xFC0) >>6) | $f;
        $c5 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2).chr($c3).chr($c4).chr($c5);
    }
    //U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    else if($unicode_c_val >= 0x4000000 && $unicode_c_val <= 0x7FFFFFFF){         $h=0xFC; // 11111100
        $c1 = $unicode_c_val >> 30 | $h;
        $c2 = (($unicode_c_val & 0x3F000000)>>24) | $f;
        $c3 = (($unicode_c_val & 0xFC0000)>>18) | $f;
        $c4 = (($unicode_c_val & 0x3F000) >>12) | $f;
        $c5 = (($unicode_c_val & 0xFC0) >>6) | $f;
        $c6 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2).chr($c3).chr($c4).chr($c5).chr($c6);
    }
    return $str;
}
function entities2utf8($unicode_c){
    $unicode_c = preg_replace("/\&\#([\da-f]{5})\;/es", "entity2utf8onechar('\\1')", $unicode_c);
    return $unicode_c;
}
17赞 masakielastic 1/16/2015 #4
$str = '\u0063\u0061\u0074'.'\ud83d\ude38';
$str2 = '\u0063\u0061\u0074'.'\ud83d';

// U+1F638
var_dump(
    "cat\xF0\x9F\x98\xB8" === escape_sequence_decode($str),
    "cat\xEF\xBF\xBD" === escape_sequence_decode($str2)
);

function escape_sequence_decode($str) {

    // [U+D800 - U+DBFF][U+DC00 - U+DFFF]|[U+0000 - U+FFFF]
    $regex = '/\\\u([dD][89abAB][\da-fA-F]{2})\\\u([dD][c-fC-F][\da-fA-F]{2})
              |\\\u([\da-fA-F]{4})/sx';

    return preg_replace_callback($regex, function($matches) {

        if (isset($matches[3])) {
            $cp = hexdec($matches[3]);
        } else {
            $lead = hexdec($matches[1]);
            $trail = hexdec($matches[2]);

            // http://unicode.org/faq/utf_bom.html#utf16-4
            $cp = ($lead << 10) + $trail + 0x10000 - (0xD800 << 10) - 0xDC00;
        }

        // https://tools.ietf.org/html/rfc3629#section-3
        // Characters between U+D800 and U+DFFF are not allowed in UTF-8
        if ($cp > 0xD7FF && 0xE000 > $cp) {
            $cp = 0xFFFD;
        }

        // https://github.com/php/php-src/blob/php-5.6.4/ext/standard/html.c#L471
        // php_utf32_utf8(unsigned char *buf, unsigned k)

        if ($cp < 0x80) {
            return chr($cp);
        } else if ($cp < 0xA0) {
            return chr(0xC0 | $cp >> 6).chr(0x80 | $cp & 0x3F);
        }

        return html_entity_decode('&#'.$cp.';');
    }, $str);
}

评论

1赞 c00000fd 4/23/2020
谢谢。这似乎适用于补充字符,例如😍
0赞 NoLoHo 2/16/2022
这似乎是唯一适用于我的用例的答案:解码字符串中的 unicode 转义序列。谢谢!
2赞 Nemo Noman 3/6/2015 #5

这是一种用 HTML 替换原始 UNICODE 的大锤方法。我还没有看到任何其他地方可以放置此解决方案,但我认为其他人也遇到过这个问题。

在执行任何操作之前,将此str_replace函数应用于 RAW JSON 还。

function unicode2html($str){
    $i=65535;
    while($i>0){
        $hex=dechex($i);
        $str=str_replace("\u$hex","&#$i;",$str);
        $i--;
     }
     return $str;
}

这不会像您想象的那么长,这将用 HTML 替换任何 unicode。

当然,如果您知道 JSON 中返回的 unicode 类型,则可以减少这种情况。

例如,我的代码得到了很多箭头和 dingbat unicode。 这些介于 8448 和 11263 之间。因此,我的生产代码如下所示:

$i=11263;
while($i>08448){
    ...etc...

您可以在此处按类型查找 Unicode 块: http://unicode-table.com/en/ 如果您知道您正在翻译阿拉伯语或 Telegu 或其他代码,您可以替换这些代码,而不是全部 65,000 个。

您可以将同样的大锤应用于简单编码:

 $str=str_replace("\u$hex",chr($i),$str);
1赞 orel 1/25/2017 #6

修复 JSON 值, 它是在 u{xxx} 之前将 \ 添加到所有 +“ ”

  $item = preg_replace_callback('/"(.+?)":"(u.+?)",/', function ($matches) {
        $matches[2] = preg_replace('/(u)/', '\u', $matches[2]);
            $matches[2] = preg_replace('/(")/', '&quot;', $matches[2]); 
            $matches[2] = json_decode('"' . $matches[2] . '"'); 
            return '"' . $matches[1] . '":"' . $matches[2] . '",';
        }, $item);
26赞 Rabin Lama Dong 7/6/2017 #7

菲律宾比索 7+

从 PHP 7 开始,您可以使用 Unicode 代码点转义语法来执行此操作。

echo "\u{00ed}";输出。í

评论

3赞 Gus 11/7/2018
谢谢!比其他答案简单得多
0赞 Sergey Yurich 6/30/2023 #8

有一个非常简单而美丽的解决方案。

如果我们想像这样解码Unicode转义序列,我们可以使用简单的函数:"\u00ed""í"json_decode

$a="\u00ed";
echo json_decode("\"$a\"");
# output: í

它之所以有效,是因为将所有非 utf-8 符号编码为序列:json_encode\u****

echo json_encode("í");
# output: "\u00ed"

这是解决方案 https://stackoverflow.com/a/7981441/5599052 的一点延续。

评论

0赞 Your Common Sense 6/30/2023
stackoverflow.com/a/7981441/285587