PHP 原生的 json_encode
方法對中文進行編碼的時候,不加參數 JSON_UNESCAPED_UNICODE
獲得一串類 \uXXXX
的字符串,加參數則是咱們一般看到的中文,發生了什麼?php
//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
編碼的轉義。即,html
展現正常的 好
是utf-8
編碼;linux
\u597d
單個字符(有6個)拎出來傳輸的時候也都是 utf-8
編碼,但在具體解析的時候,判斷出有轉義,將\
、u
、5
、9
、7
、d
這6個字符合在一塊兒,做爲utf-16
編碼。json
json_encode
加參數 JSON_UNESCAPED_UNICODE
,不對字符進行 utf-16
轉義,直接使用 utf-8
。因爲沒有使用轉義,整個字符串大小也由8字節變小爲5字節。緣由是轉義字符 \u597d
中每一個字符佔了1字節,一共是6字節,而 好
的utf-8
編碼只有3字節,少用了3字節。segmentfault
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碼點
)。