關於坑爹的編解碼問題

編解碼問題歷來都是搞IT,尤爲是搞互聯網的同志們的心頭之痛。君不見,http請求,數據庫字符,中文亂碼等東西,都和字符編碼有偌大的關係。html

這個坑貌似是躲不過了。因此最好的方式就是:直面它,解決它。你說是否是~java

首先解決一些基礎概念問題。utf8 unicode ascii之間究竟是什麼關係?數據庫

若是這個不搞清楚,你就老是會問,我怎麼把utf8轉成unicode這類表述並不嚴謹的問題。json

首先要明確一點,unicode是一種「編碼」,所謂編碼就是一個編號(數字)到字符的一種映射關係,就僅僅是一種一對一的映射而已,能夠理解成一個很大的對應表格。unicode 只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。數組

UTF-8 是在互聯網上使用最廣的一種 Unicode 的實現方式。其餘實現方式還包括 UTF-16(字符用兩個字節或四個字節表示)和 UTF-32(字符用四個字節表示),注意,UTF-8 是 Unicode 的實現方式之一。換一句話說,GBK、UTF-8是一種「編碼格式」,是用來序列化或存儲1中提到的那個「編號(數字)」的一種「格式」;GBK和UTF-8都是用來序列化或存儲unicode編碼的數據的,可是分別是2種不一樣的格式; 他們倆除了格式不同以外,他們所關心的unicode編碼範圍也不同,utf-8考慮了不少種不一樣國家的字符,涵蓋整個unicode碼錶,因此其存儲一個字符的編碼的時候,使用的字節長度也從1字節到4字節不等;而GBK只考慮中文——在unicode中的一小部分——的字符,的編碼,因此它算好了只要2個字節就能涵蓋到絕大多數經常使用中文(2個字節能表示6w多種字符),因此它存儲一個字符的時候,所用的字節長度是固定的;網絡

所謂encode,是將邏輯上的字符,例如「a」,轉化爲一系列二進制串,能夠用utf8,也能夠用ascii等等。編碼

所謂decode,就是將上述一系列的二進制串,轉爲邏輯上的字符。翻譯

二者是互逆的過程。code

結合java來看一下,首先java的string使用的編碼是unicode,可是,當string存在於內存中時(也就是當程序運行時、你在代碼中用string類型的引用對它進行操做時、也就是string沒有被存在文件中且也沒有在網絡中傳輸(序列化)時),是「只有編碼而沒有編碼格式的」,因此java程序中的任何String對象,說它是gbk仍是utf-8都是錯的,gbk和utf-8是編碼格式而不是編碼,String在內存中不須要「編碼格式」(記住編碼格式是在存文件或序列化的時候使用的), 它只是一個unicode的字符串而已。server

因此java裏面String是不帶編碼格式的,而String.toByteArray(charsetName)獲得的byteArray是帶編碼格式的(還有一種方法叫getBytes),格式就是你傳入的'charsetName',咱們不妨把toByteArray的這個過程叫作「編碼」,就是上面說的encode;另外,new String(byte[], charsetName)是把一個byte數組(帶編碼格式)以charsetName指定的編碼格式翻譯爲一個不帶編碼格式的String對象,咱們不妨把這個過程叫「解碼」,就是上面說的decode。

具體到實際的例子,例如數據庫,使用characterEncoding=utf8作鏈接參數,便是表示在數據庫和server之間的傳輸的字節,都是utf8編碼的。

在java中,若是你寫下String str ="\u4f60\u597d",那麼本質上,是表明「你好」兩個漢字。\u做爲的是轉義字符,所指就是unicode編碼。

在轉爲json的過程當中,例如使用gson這個三方庫的時候,它會自動將其序列化爲unicode的字符串。沒有utf8的編碼,就是\u4f60這個字符常量(as it is)

若是想要打印出某個char的unicode碼,在java中能夠直接轉爲int類型後打印,由於 The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).

 

ref:

1] https://www.zhihu.com/question/20361462

2] http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

相關文章
相關標籤/搜索