Ruby String 是怎麼儲存的?
以 Java 為例,他的字串編碼清一色是 Unicode,所以一個字佔 2 bytes,想問 Ruby 也是使用 Unicode 嗎?
有什麼方法可以知道他的字串在記憶體裡面是怎麼儲存的?
http://patshaughnessy.net/2012/1/4/never-create-ruby-strings-longer-than-23-characters 有講一些,不過跟編碼無關,我得回去查一下書
書上有提到 Ruby 不是統一用 Unicode 方式存字串,每個string都能有自己的編碼方式。
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
我發現網路上很多轉換工具觀念都是錯的……他們說轉成 utf-8,實際上只是給我 unicode 編號而已。
補一個剛剛看到的,關於 Unicode 和 UTF-8 的知識文,昨天剛刊登的,參考一下:
http://coding.smashingmagazine.com/2012/06/06/all-about-unicode-utf8-character-sets/