JSON 序列化中的轉義和 Unicode 編碼

本文比較完整地整理一下 JSON 編碼中的轉義,以及 JSON 對 Unicode 編碼的處理。javascript

其實這是我上一篇文章的姊妹篇。在研究 Unicode 顏文字的時候,因爲咱們的數據傳輸是經過 JSON 串來完成的,在對顏文字進行轉碼傳輸的過程當中,也發現了一個問題。解決問題以後,便有了本總結文。java

JSON 中的普通轉義字符

我的認爲,JSON 是目前針對程序員而言可讀性(readability)最佳的數據傳輸格式之一,而且 JSON 完整地考慮到了數據傳輸中的轉義,避免出現各類注入風險。當對 JSON 進行序列化操做時(Go 中稱爲 marshal),根據 JSON 標準的說明,須要對字符串中的如下字符進行轉義:程序員

符號 名稱 轉義後的字符串
" 雙引號 \"
/ 斜槓 \/
\ 反斜槓 \\
\b 退格符 \b
\f 垂直製表符 \f
Tab 水平製表符 \t
\r 回車 \r
\n 換行符 \n
< 左尖括號 \u003C
> 右尖括號 \u003E
& And 符號 \u0026

另外針對 Go 語言,我的建議再轉義一個百分號 %\u0025,緣由是在 Go 的各類字符串格式化操做中,百分號是一個關鍵字符,這樣能夠避免在打日誌或者其餘設計格式化的操做時出現錯誤。編程

JSON 中針對 Unicode 字符的處理

這裏所說的 Unicode 字符,準確而言指的是在 ASCII 範圍以外的字符,也就是值大於 0x7F 的 Unicode 字符。json

其實大部分狀況下,UTF-8 已經成爲現代編程語言約定俗成的標準了,所以在 JSON 序列化時,只要簡單地對 Unicode 字符的值轉爲二進制而後按照網絡字節序打包就能夠了。segmentfault

可是在某些狀況下,當對端採用的不是 UTF-8,或者是對端採用的不是網絡字節序時(好比對方是技術底下/落後、但卻話語權強大的客戶/合做商/集成商),這個時候,你們統一採用 ASCII 編碼,就可以避免這些問題了。網絡

那麼 JSON 是怎麼使用 ASCII 編碼來傳輸 Unicode 的呢?從前文的轉義其實就能夠一窺端倪了——JSON 採用的是 \uXXXX 的形式來表示一個 Unicode 字符的。每一個 Unicode 字符表示法中,XXXX 必須是4個十六進制數,即使高位爲0也須要補全。經過這種方式,編碼和傳輸 Unicode 字符。在 ASCII 爲主的數據傳輸中,這種編碼方式比較穩妥,而且不會額外增長過多的數據量。固然對於 Unicode 字符比較多的狀況下(好比大量的中文),這就須要程序員考慮一下額外帶來的網絡花銷了。編程語言

大於 0xFFFF 的 Unicode 字符的編碼

讀者可能會注意到了,\uXXXX 格式最大隻能支持到 0xFFFF,但 Unicode 早就已經超過了這個範圍。大於 65535 的字符要怎麼表示呢?首先,絕對不是簡單地採用 uXXXXX,這會致使編碼錯誤。編碼

針對大於 65535 的字符,JSON 採用的是 UTF-16 編碼。UTF-16 採用了 Unicode 的一個特性:不超過20位。
好比咱們用 u 表明這樣的一個字符,UTF-16 的處理方法以下:spa

  • 首先,u = u - 0x10000
  • hi 等於作了減法以後的 u 的高10位:hi = (u & 0xFFC00) >> 10
  • lo 等於作了減法以後的 u 的低10位:lo = u & 0x003FF
  • 高位加上 0xD800 後進行 \u 編碼
  • 低位加上 0xDC00 後進行 \u 編碼

舉例說明:表明地球的顏文字符號 「🌍」,其編碼值爲 0x1F30D,按照 UTF-16 編碼過程爲:

  • u = 0x1F30D - 0x10000 = 0xF30D,二進制爲:1111 0011 0000 1101
  • 高10位等於 0000111100,低10位等於 1100001101
  • 高位值 0x03C 作加法以後等於 0xD83C
  • 低位值 0x30D 作加法以後等於 0xDF0D
  • 最終編碼爲 \uD83C\uDF0D

好比如下的 JSON:

{
    "string":"我是地球🌍"
}

按照 ASCII 序列化以後,結果爲:

{"string":"\u6211\u662F\u5730\u7403\uD83C\uDF0D"}

參考資料


本文章採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。

原做者: amc,歡迎轉載,但請註明出處。

原文標題:JSON 序列化中的轉義和 Unicode 編碼

發佈日期:2020-05-31

本文連接:http://www.javashuo.com/article/p-snrvsutk-mz.html

本文最先發佈於:https://cloud.tencent.com/developer/article/1336510,也是本人的博客

Copyright

相關文章
相關標籤/搜索