提出问题
PHP 原生的 json_encode
方法对中文进行编码的时候,不加参数 JSON_UNESCAPED_UNICODE
得到一串类 \uXXXX
的字符串,加参数则是我们通常看到的中文,发生了什么?
确认现象
//1.php
<?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
<?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码点
)。
参考
- json 标准 http://www.json.org.cn/standa...
- 字符编码笔记:ASCII,Unicode 和 UTF-8 http://www.ruanyifeng.com/blo...
- Unicode与JavaScript详解 http://www.ruanyifeng.com/blo...
- JSON 序列化中的转义和 Unicode 编码 https://segmentfault.com/a/11...
- 鸟哥的让Json更懂中文(JSON_UNESCAPED_UNICODE) https://www.laruence.com/2011...
- 在线转换中文转utf-8编码16进制、Unicode编码16进制 http://www.mytju.com/classcod...
- 在线转换中文转Unicode编码16进制(这个网站误导人,实际上是转成了Unicode编码16进制,缺偏偏说成是utf-8) https://utf8.supfree.net/
- ascii 码表的对照 http://ascii.911cha.com/
- linux od工具,查看文件的二进制格式 https://wangchujiang.com/linu...
- Linux命令学习总结:hexdump https://www.cnblogs.com/kerry...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。