【问题标题】:Convert Unicode from JSON string with PHP使用 PHP 从 JSON 字符串转换 Unicode
【发布时间】:2013-01-09 12:53:42
【问题描述】:

我一直在阅读一些解决方案,但尚未设法使任何工作。

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

【问题讨论】:

  • 这听起来像是 API 的另一端的编码被破坏了。如果您采用 UTF-8 编码数据并将其读取为 ISO-8859-1,通常会得到 £。我猜在结果字符串被 JSON 编码之前,这发生在 API 提供者系统的某个地方。有点乱,真的。第一个呼叫端口应该是通知 API 提供者并要求他们修复它。
  • 感谢 SDC。我给他们发了一封电子邮件来说明这一点。希望它会尽快更新,但也许这是一厢情愿的想法!

标签: php unicode encoding utf-8 character-encoding


【解决方案1】:

输出是正确的。

\u00c2 == Â
\u00a3 == £

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

htmlentities($title);

【讨论】:

  • 第一部分是正确的,但是 htmlentities($title) 给了我 ã
  • 输出是正确的,但很明显,将原始 UTF-8 字符串编码为 JSON 的软件忽略了它是 UTF-8 并将每个字节盲目编码为转义的 unicode 代码这一事实点。
  • 仅供参考,JSON 来自 Hot UK Deals API。我不想搞乱默认的 XML 提要类型
【解决方案2】:

不是 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 之后。

【讨论】:

  • 谢谢。我可以在调用 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" 的格式吗?
【解决方案3】:

这里是使用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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 2011-06-09
    • 2015-11-24
    • 1970-01-01
    相关资源
    最近更新 更多