使用 PHP 从 JSON 字符串转换 Unicode


Convert Unicode from JSON string with PHP

我一直在阅读一些解决方案,但还没有设法让任何东西工作。

我有一个从 API 调用中读入的 JSON 字符串,它包含 Unicode 字符 - 例如'u00c2'u00a3是 £ 符号。

我想使用 PHP 将它们转换为 ££ .

我正在调查这个问题并找到了以下代码(使用我的井号进行测试),但它似乎不起作用:

$title = preg_replace("/''''u([a-f0-9]{4})/e", "iconv('UCS-4LE','UTF-8',pack('V', hexdec('U$1')))", ''u00c2'u00a3');

输出为 £

我认为这是 UTF-16 编码是否正确?如何将这些转换为输出为 HTML?

更新

似乎来自 API 的 JSON 字符串有 2 或 3 个未转义的 Unicode 字符串,例如:

That'u00e2'u0080'u0099s (right single quotation)
'u00c2'u00a (pound symbol)

不是 UTF-16 编码。它看起来像是虚假编码,因为''uXXXX编码独立于Unicode的任何UTF或UCS编码。 'u00c2'u00a3真正映射到£字符串。

你应该拥有的是'u00a3哪个是 £ 的 unicode 代码点。

{0xC2, 0xA3} 是此代码点的 UTF-8 编码的 2 字节字符。

如果,正如我认为的那样,将原始 UTF-8 字符串编码为 JSON 的软件忘记了它是 UTF-8 的事实,并且盲目地将每个字节编码为转义的 unicode 码位,那么您需要将每对 unicode 码位转换为 UTF-8 编码字符,然后将其解码为本机 PHP 编码以使其可打印。

function fixBadUnicode($str) {
    return utf8_decode(preg_replace("/''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})/e", 'chr(hexdec("$1")).chr(hexdec("$2"))', $str));
}

此处的示例:http://phpfiddle.org/main/code/6sq-rkn

编辑:

如果要修复字符串以获取有效的 JSON 字符串,则需要使用以下函数:

function fixBadUnicodeForJson($str) {
    $str = preg_replace("/''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})/e", 'chr(hexdec("$1")).chr(hexdec("$2")).chr(hexdec("$3")).chr(hexdec("$4"))', $str);
    $str = preg_replace("/''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})/e", 'chr(hexdec("$1")).chr(hexdec("$2")).chr(hexdec("$3"))', $str);
    $str = preg_replace("/''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})/e", 'chr(hexdec("$1")).chr(hexdec("$2"))', $str);
    $str = preg_replace("/''''u00([0-9a-f]{2})/e", 'chr(hexdec("$1"))', $str);
    return $str;
}

编辑 2:修复了前面的函数,将任何错误的 unicode 转义 utf-8 字节序列转换为等效的 utf-8 字符。

请注意,其中一些字符(可能来自 Word 等编辑器)无法转换为 ISO-8859-1,因此将在ut8_decode后显示为"?"。

输出正确。

'u00c2 == Â
'u00a3 == £

所以这里没有错。转换为 HTML 实体很容易:

htmlentities($title);

这是使用该函数的更新版本,使用 preg_replace_callback 而不是 preg_replace

function fixBadUnicodeForJson($str) {
    $str = preg_replace_callback(
    '/''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})/',
    function($matches) { return chr(hexdec("$1")).chr(hexdec("$2")).chr(hexdec("$3")).chr(hexdec("$4")); },
    $str
);
    $str = preg_replace_callback(
    '/''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})/',
    function($matches) { return chr(hexdec("$1")).chr(hexdec("$2")).chr(hexdec("$3")); },
    $str
);
    $str = preg_replace_callback(
    '/''''u00([0-9a-f]{2})''''u00([0-9a-f]{2})/',
    function($matches) { return chr(hexdec("$1")).chr(hexdec("$2")); },
    $str
);
    $str = preg_replace_callback(
    '/''''u00([0-9a-f]{2})/',
    function($matches) { return chr(hexdec("$1")); },
    $str
);
    return $str;
}