Unicode學習筆記

,發表於2016-11-02

雖然從事了幾年程式開發工作,但是很慚愧,對於字元編碼如Unicode的知識一直存在很大的盲點,比如搞不清楚Unicode碼點和具體編碼方案的關係。最近下決心把這一塊兒知識補一補,學習資料用的是Joel Spolsky的一篇博文

記錄要點如下:

  1. 在Unicode字符集中,每一個字元都有一個唯一編碼,稱為碼點(Unicode code point)。表示一個Unicode值的十六進位制數通常在前面加上“U+”,例如“U+0041”代表字元“A”。
  2. 字元與碼點是一一對應關係。碼點相當於為字元賦予了一個唯一的ID值,是一種抽象,並沒有規定字元具體的編碼型別。字串必然對應一種編碼型別。在實際應用中,談到具體某一個字串的時候,需要同時指明其編碼型別。只談字串不談編碼型別就是耍流氓。(It does not make sense to have a string without knowing what encoding it uses. —— by Joel Spolsky)
  3. 目前較為常見的字元編碼形式是UTF-8。 UTF-8是不定長編碼形式。可以無縫相容ASCII。
  4. 在網路傳輸中使用的也是UTF-8編碼形式。
  5. 網頁可以通過兩種形式指定編碼型別。一種是通過HTTP頭: Content-Type,另外一種是通過<meta>標籤——通常它出現於網頁開始的地方;瀏覽器先使用ASCII的格式讀取,然後停止渲染,重新解碼。

簡單理解就是,碼點相當於給每個字元在數軸上定義了一個座標。而編碼方式相當於一套加密解密規則。因為資料都是以位元組的形式來進行儲存和傳輸的,我們在獲取到一堆位元組之後,需要將其解釋為有意義的字元(如果可能的話),那麼就需要知曉其編碼規則。如果編碼規則不合適,就會出現亂碼的情況。

下面是一些具體的程式碼示例。以“圖靈”二字為例,其中,“圖”字和“靈”字的碼點的如下圖所示: enter image description hereenter image description here

在Python 2中:

>> str = u'圖靈'
>> str
u'\u56fe\u7075' #碼點值
>> print u'\u56fe\u7075'
圖靈
>> print unichr(0x56fe) + unichr(0x7075)
圖靈
>> str.encode('utf-8') 
'\xe5\x9b\xbe\xe7\x81\xb5' #UTF-8編碼值
>> print '\xe5\x9b\xbe\xe7\x81\xb5'.decode('utf-8') 
圖靈

Rebol 3Red中:

>> to string! #{e59bbee781b5}
==  "圖靈"
>> to binary! "圖靈"
== #{E59BBEE781B5}
>> "^(56fe)^(7075)"  #使用碼點
== "圖靈"

在 NodeJS 中:

var buf = Buffer.from('圖靈');    //<Buffer e5 9b be e7 81 b5>
console.log(buf.toString('utf8'));    //'圖靈'

var buf2 = Buffer.from('\u56fe\u7075'); //使用碼點
console.log(buf2.toString('utf8'));   //'圖靈'

var buf3 = Buffer.allocUnsafe(256);
var len = buf3.write('\u56fe\u7075', 0);
console.log(`${len} bytes: ${buf3.toString('utf8', 0, len)}`);  //6 bytes: 圖靈

var buf4 = Buffer.from([0xe5, 0x9b, 0xbe, 0xe7, 0x81, 0xb5]);
console.log(buf4.toString('utf8'));   //'圖靈'

//gbk
const iconv = require('iconv-lite');
var text = iconv.decode(new Buffer([0xCD, 0xBC, 0xC1, 0xE9]), 'gbk')
console.log(text);  //'圖靈'

在Java中:

byte[] bytes 
    = new byte[]{(byte)0xe5, (byte)0x9b, (byte)0xbe, (byte)0xe7, (byte)0x81, (byte)0xb5};
System.out.println(new String( bytes,  "utf-8")); //圖靈
System.out.println(
    Arrays.toString("圖靈".getBytes("utf-8"))
); 
//[-27, -101, -66, -25, -127, -75]

相關文章