2a01ae9942939ee2b3954a6727d2bb92

Ruby String 是怎麼儲存的?

2012-06-06 13:01:29 +0800tonytonyjanRuby 節點 中發起
最後由 chitsaou2012-06-08 00:56:48 +0800回應 , 391次閱讀

以 Java 為例,他的字串編碼清一色是 Unicode,所以一個字佔 2 bytes,想問 Ruby 也是使用 Unicode 嗎?

有什麼方法可以知道他的字串在記憶體裡面是怎麼儲存的?

截至 2012-06-08 00:56:48 +0800,共收到 6 條回應
009994c3985985809d2d644bd49aa1c2
lulalala 1樓, 於2012-06-06 13:54:35 +0800回應

http://patshaughnessy.net/2012/1/4/never-create-ruby-strings-longer-than-23-characters 有講一些,不過跟編碼無關,我得回去查一下書

009994c3985985809d2d644bd49aa1c2
lulalala 2樓, 於2012-06-06 20:37:03 +0800回應

書上有提到 Ruby 不是統一用 Unicode 方式存字串,每個string都能有自己的編碼方式。

36b1f565fc83d9b67588123f2171b896
chitsaou 3樓, 於2012-06-06 22:14:33 +0800回應

Unicode 跟幾個 bytes 無關。Unicode 只規定字的編號 (U+00XX) 跟長相,實際上編碼不一定是 2 bytes 。

以 UTF-8 為例,傳統 ANSI 字元 (U+0000 - U+007F) 是編成 1-byte ,U+0080 - U+07FF 是編成 2-byte, U+0800 - U+FFFF 是編成 3 個 bytes ,再往上還有 4 bytes 、 5 bytes ,根據 Unicode 的 code point 而伸縮。

我們常用的漢字以及日文假名都落在 U+0800 - U+FFFF 之間,所以是編成 3 bytes ,不是 2 bytes 。而實際上我們常用的字元也大都落在 U+0000 - U+FFFF 之間(叫做 BMP,http://en.wikipedia.org/wiki/Basic_Multilingual_Plane);至於 U+10000 以上的字是補充字元,有一大片給了漢字裡的罕用字、古字,沒有安裝相對應的字體(如新細明體 Ext-B)是看不到也打不出來的。

Java 我記得是用 UTF-16 ,這種編碼方式會統一編成 16-bit 也就是你說的 2 bytes 。Windows 的記事本預設也是儲存成 UTF-16 ,而它另一個選項是 UTF-8 with BOM ,但實務上 UTF-8 不需要 BOM (因為沒有 byte order 的問題)。

回到 Ruby , Ruby 1.9 以後引入了 Encoding class ,每個 String instance 都有它自己的 encoding ,它儲存的只是原始的 byte ,然後 instance 裡面會記錄是哪個 encoding ,所以實際上你要用什麼編碼去解都行,也可以透過它內建的編碼轉碼器去轉;而這也比較接近實際電腦處理字串的方式。

> "漢字".encoding
 => #<Encoding:UTF-8> 
> "漢字".encode("Big5")
 => "\x{BA7E}\x{A672}" 
> "漢字".bytes {|byte| printf "0x%X ", byte}
0xE6 0xBC 0xA2 0xE5 0xAD 0x97  => "漢字" 
> "\xE6\xBC\xA2\xE5\xAD\x97"
 => "漢字" 

題外話, MySQL 的 UTF-8 只能儲存 BMP (U+0000 ~ U+FFFF) 的字元,U+10000 以上的字元它不能儲存(http://dev.mysql.com/doc/refman//5.5/en/charset-unicode.html)。

see also:

約耳談軟體:人人都應該知道的 Unicode 知識:
http://local.joelonsoftware.com/wiki/The_Joel_on_Software_Translation_Project:%E8%90%AC%E5%9C%8B%E7%A2%BC

UTF-8 - Wikipedia
http://en.wikipedia.org/wiki/UTF-8

UTF-16 - Wikipedia
http://en.wikipedia.org/wiki/UTF-16

Ruby 的 Encoding class:
http://ruby-doc.org/core-1.9.3/Encoding.html

2a01ae9942939ee2b3954a6727d2bb92
tonytonyjan 4樓, 於2012-06-07 00:42:05 +0800回應

#3樓 @chitsaou 真的非常的感謝你,解了困擾我多時的問題,還有導正 unicode 的觀念!

2a01ae9942939ee2b3954a6727d2bb92
tonytonyjan 5樓, 於2012-06-07 01:40:22 +0800回應

我發現網路上很多轉換工具觀念都是錯的……他們說轉成 utf-8,實際上只是給我 unicode 編號而已。

36b1f565fc83d9b67588123f2171b896
chitsaou 6樓, 於2012-06-08 00:56:48 +0800回應

補一個剛剛看到的,關於 Unicode 和 UTF-8 的知識文,昨天剛刊登的,參考一下:
http://coding.smashingmagazine.com/2012/06/06/all-about-unicode-utf8-character-sets/

需要 登入 後方可回應,如果你還沒有帳號按這裡 註冊