为什么json_decode转换我的unicode字符串?

时间:2019-07-03 15:04:58

标签: php json unicode

我有一个带Unicode字符的字符串。

例如:

$s = '"x9gtjw\u001d91ffd0\u001d92K"';
var_dump($s, json_decode($s));

这给出了输出:

string '"x9gtjw\u001d91ffd0\u001d92K"' (length=29)
string 'x9gtjw91ffd092K' (length=17)

为什么json_decode转换我的unicode符号?

我正在使用PHP 7.2。

我尝试使用标志(例如JSON_INVALID_UTF8_SUBSTITUTE),但它们没有帮助。

更新:

我需要使用json_decode而不将\uXXXX转换为十六进制\xXX

例如:

$s = '{"code":"zz\u001d"}';
$json = json_decode($s);
if($json->code == 'zz\u001d') {...}

字符串$s包含不可见的字符\x1d

我尝试将反斜杠转换为双反斜杠-这对输出没有影响。

2 个答案:

答案 0 :(得分:1)

字符仍然存在于解码字符串string 'x9gtjw91ffd092K' (length=17)中,但未显示。 1D是用于组分隔符(不可打印的字符)的ASCII控制代码。

请注意,由于UTF-8字符为\x1d,并且字符串中有两个,因此字符串长度的大小比显示的字符串(15)大两个(17)。

如果字符为:\u0A1(倒置感叹号),则UTF-8版本将增加2个额外的字节(\xc2\xa1)。最多可以存在4个额外的字节(较高的UTF-32 Emojis)。

您的比较不起作用,因为:

您必须将双反斜杠\\\\加倍才能转义Unicode编码。

$s = '{"code":"zz\\\\u001d"}';
$json = json_decode($s);
if($json->code == 'zz\u001d') {...}

否则\u001d将在解码时解释。

在此说明更自然的方法(不是问什么,但仍然是解决方案):

PHP包含\uXXXX转义序列。Reference("Double quoted" section, 1 page down )时,需要双引号

只需按照以下要求更改检测代码:

$s = '{"code":"zz\u001d"}';
$json = json_decode($s);
if($json->code == "zz\u001d") {...}

{...}中给出的代码现在将运行。

答案 1 :(得分:1)

您的字符串$s(它们都是!)不包含任何“不可见字符\ x1d”(根据ASCII的组分隔符(GS))。它们都包含一个文字反斜杠,后跟字母“ u”等。

现在,那里还有什么不对劲:如果打印字符串'a\x0ab',您将得到它的原样,减去引号。如果您打印字符串"a\x0ax",则将得到一个“ a”和一个“ b”,以换行符分隔。在PHP中,带单引号的字符串文字与带双引号的字符串文字有所不同。

现在,您可能想知道如何避免json_decode()解释\uxxxx序列。一个简单的答案是:您不能,因为那将违反JSON规范,并且没有理智的解析器会这样做。您基本上可以做两件事:

  1. 修复输入中包含反斜杠的问题,该反斜杠不是转义序列的一部分。这意味着,您必须在输入字符串中将反斜杠加倍。由于在PHP中,反斜杠也被解释为转义符号,因此您必须将其加倍。您可以看到,如果您使用json_encode()对预期结果进行编码。
  2. 修复您要对输出执行的任何操作。问自己,为什么想要输出字符串中的某些内容不希望由JSON表示,例如控制字符,这些字符已被明确排除。如果只是因为您无法显示它,或者是因为它弄乱了某种格式,那么请确保在输出它时一切正常,但不要将内部表示更改为违反直觉的东西。