使用PHP从JSON字符串转换Unicode

使用PHP从JSON字符串转换Unicode,php,unicode,encoding,utf-8,character-encoding,Php,Unicode,Encoding,Utf 8,Character Encoding,我一直在阅读一些解决方案,但到目前为止还没有找到任何可行的方法 我有一个从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')))", '\

我一直在阅读一些解决方案,但到目前为止还没有找到任何可行的方法

我有一个从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)

输出是正确的

\u00c2 == Â
\u00a3 == £
所以这里没有什么问题。转换为HTML实体很容易:

htmlentities($title);

它不是UTF-16编码。这看起来像是伪造的编码,因为\uxxx编码与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));
}
示例如下:

编辑:

如果要修复该字符串以获得有效的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_解码后将显示为“?”。

以下是使用
preg_replace_回调
而不是
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;
}

第一部分是正确的,但是htmlentities($title)给了我Ã�输出是正确的,但很明显,将原始UTF-8字符串编码为JSON的软件没有意识到它是UTF-8,而是盲目地将每个字节编码为转义的unicode代码点。仅供参考,JSON来自热门的UK Deals API。我不想弄乱默认的XML提要类型,谢谢。在调用json_decode保存多次调用'fixBadUnicode'之前|之后,我可以在整个字符串上运行它吗?您可以在json_decode之前运行它,但是要小心,这可能会导致您的json字符串包含非法字符,请参阅json.org以获取json字符串中可能存在的字符列表。如果我在原始json上运行它,它将'\u00c2\u00a3'转换为'�'. 我还发现\u0099保持不变-我认为这是一个撇号。似乎是一个非常糟糕的JSON数据源!太好了,谢谢你。在“修复”后,我不需要编码的JSON,因为我需要遍历数据。我可以改为调用json_decode然后preg_replace(…)而不需要调用json_encode并且substr?preg_replace“e”已被弃用,您可以用“preg_replace_callback”的格式编写它吗?听起来好像API的另一端的编码被破坏了<代码>通常是您获取UTF-8编码数据并将其作为ISO-8859-1读取时得到的。我猜在生成的字符串被JSON编码之前,API提供者的系统中的某个地方就会发生这种情况。真的有点乱。第一个调用端口应该是通知API提供者并要求他们修复它。谢谢SDC。我给他们发了一封电子邮件,告诉他们这一点。希望它会很快更新,但也许这是一厢情愿的想法!