php json json_unescaped_unicode,json_encode 使用 JSON_UNESCAPED_UNICODE

提出问题

PHP 原生的 json_encode 方法对中文进行编码的时候,不加参数 JSON_UNESCAPED_UNICODE 得到一串类 \uXXXX 的字符串,加参数则是我们通常看到的中文,发生了什么?

确认现象

//1.php

echo json_encode('好');

# php 1.php > 1.txt

# ls -l 1.txt

-rw-r--r-- 1 root root 8 Jun 12 15:21 1.txt

# cat 1.txt

"\u597d"

//2.php

echo json_encode('好', JSON_UNESCAPED_UNICODE);

php 2.php > 2.txt

# ls -l 2.txt

-rw-r--r-- 1 root root 5 Jun 12 15:23 2.txt

# cat 2.txt

"好"

先说结论

我们通常使用的 json 格式都是 utf-8 编码,但它认可 utf-16 编码的转义。即,

展示正常的 好 是utf-8编码;

\u597d 单个字符(有6个)拎出来传输的时候也都是 utf-8 编码,但在具体解析的时候,判断出有转义,将\、u、5、9、7、d这6个字符合在一起,作为utf-16编码。

json_encode 加参数 JSON_UNESCAPED_UNICODE,不对字符进行 utf-16 转义,直接使用 utf-8。由于没有使用转义,整个字符串大小也由8字节变小为5字节。原因是转义字符 \u597d 中每个字符占了1字节,一共是6字节,而 好 的utf-8编码只有3字节,少用了3字节。

验证

hexdump 可以查看文本文件以二进制格式。以下的 -c 参数,如果对应单字节有符合的 ascii 码,会直接以 ascii 码格式展示,否则以相应的八进制数展示;-b 参数,完全以8进制数展示每个字节。

# hexdump -c 1.txt

0000000 " \ u 5 9 7 d "

0000008

//八进制格式

# hexdump -b 1.txt

0000000 042 134 165 065 071 067 144 042

0000008

# hexdump -c 2.txt

0000000 " 345 245 275 "

0000005

//八进制格式

# hexdump -b 2.txt

0000000 042 345 245 275 042

0000005

以上使用 od -w1 -b 2.txt 有同 hexdump 差不多的效果

从上面输出不难看出,好 对应的字节八进制数应该就是 345、245、275。

转换成二进制,分别是 11100101、10100101、10111101。

二进制还可以转换成16进制数,但此处有一个字节序大小端的顾虑,哪一头开始的呢,是 275 还是 345 对应的是开头?

突破口是 好 对应的是3字节,3字节的 utf-8 编码对应的开头一定是1110(参见阮一峰的字符编码笔记:ASCII,Unicode 和 UTF-8),正好是345的开头,且字节内部也是大端。确定大端后,再联想到常说的网络字节序是大端。看了 json标准,utf-16、utf-32 都有大小端的区分,唯独 utf-8 没有,那么 utf-8 编码的 json 应该就是大端的了。(也想不出如果是小端的话,多字节字符怎么判断的好)

将二进制转换成16进制,分别是 E5、A5、BD,

找一个在线编码转换的验证 验证有没有转错了,得到结果:

字符

编码10进制

编码16进制

Unicode编码10进制

Unicode编码16进制

15050173

E5A5BD

22909

597D

E5A5BD 对上了。

另一个在线的编码转换网站 得到的转换结果是 好,这实际上 utf-8 对应的 unicode码点,不是想要的 utf-8 编码,严重误导人,网上好些在线编码网站都是这样。

一些定义说明

json 是一种传输协议,规定了一种文本组织结构,用于交互。json 常用 utf-8 编码, 但不是必须。

unicode 是一个标准,为每一个字符唯一对应定义一个 unicode码点。

utf-8、utf-16 等是针对 unicode码点 的编码方式。比如 utf-8 编码对应的字节数在1-4字节,由于短字节数量更少,所以优先分配给了越常使用的字符(unicode码点)。

参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值