Encode::Unicode -- 各種 Unicode 轉換格式
use Encode qw/encode decode/;
$ucs2 = encode("UCS-2BE", $utf8);
$utf8 = decode("UCS-2BE", $ucs2);
此模組實作 Unicode 聯盟正式文件記載的所有 Unicode 字元編碼方案(當然,除了 UTF-8 之外,它是 perl 中的原生格式)。
字元編碼方案 字元編碼形式加上位元組序列化。Unicode 中有七種字元編碼方案:UTF-8、UTF-16、UTF-16BE、UTF-16LE、UTF-32 (UCS-4)、UTF-32BE (UCS-4BE) 和 UTF-32LE (UCS-4LE),以及 UTF-7。
由於 UTF-7 是 UTF-16BE 的 7 位元(重新)編碼版本,因此它不屬於 Unicode 的字元編碼方案。它在 Encode::Unicode::UTF7 中另行實作。有關詳細資訊,請參閱 Encode::Unicode::UTF7。
Decodes from ord(N) Encodes chr(N) to...
octet/char BOM S.P d800-dfff ord > 0xffff \x{1abcd} ==
---------------+-----------------+------------------------------
UCS-2BE 2 N N is bogus Not Available
UCS-2LE 2 N N bogus Not Available
UTF-16 2/4 Y Y is S.P S.P BE/LE
UTF-16BE 2/4 N Y S.P S.P 0xd82a,0xdfcd
UTF-16LE 2/4 N Y S.P S.P 0x2ad8,0xcddf
UTF-32 4 Y - is bogus As is BE/LE
UTF-32BE 4 N - bogus As is 0x0001abcd
UTF-32LE 4 N - bogus As is 0xcdab0100
UTF-8 1-4 - - bogus >= 4 octets \xf0\x9a\af\8d
---------------+-----------------+------------------------------
你可以透過 3 個標準來分類這些 CES:每個字元的長度、位元順序和位元組順序標記。
UCS-2 是固定長度的編碼,每個字元佔用 16 位元。它不支援代理對。當在 decode() 過程中遇到代理對時,如果CHECK 為 0,其位置會填入 \x{FFFD};如果CHECK 為 1,則此例程會中斷。當遇到序數值大於 0xFFFF 的字元時,如果CHECK 為 0,其位置會填入 \x{FFFD};如果CHECK 為 1,則此例程會中斷。
UTF-16 幾乎與 UCS-2 相同,但它支援代理對。當它遇到一個高位元代理對 (0xD800-0xDBFF) 時,它會擷取下一個低位元代理對 (0xDC00-0xDFFF),並將它們desurrogate
化以形成一個字元。錯誤的代理對會導致中斷。當在 encode() 過程中遇到 \x{10000} 或以上時,它會將它們ensurrogate
化,並將代理對推入輸出串流。
UTF-32 (UCS-4) 是固定長度的編碼,每個字元佔用 32 位元。由於它是 32 位元,因此不需要代理對。
Unicode 的第一個(現在已經失敗的)目標是將所有字元庫映射到一個固定長度的整數,讓程式設計師感到滿意。由於每個字元在 C 中都是短或長,因此當你將資料傳遞給彼此時,必須注意每個平台的位元順序。
任何標記為 BE 的都是大端序(或網路位元順序),而 LE 是小端序(又稱 VAX 位元順序)。對於任何未標記為 BE 或 LE 的內容,會在字串前加上一個稱為位元組順序標記 (BOM) 的字元,以表示位元順序。
警告:儘管 utf8 中的 BOM (\xEF\xBB\xBF) 有效,但它沒有意義,而且截至撰寫本文為止,Encode 套件只會將它保留原樣 (\x{FeFF})。
16 32 bits/char
-------------------------
BE 0xFeFF 0x0000FeFF
LE 0xFFFe 0xFFFe0000
-------------------------
此模組會以以下方式處理 BOM。
當明確將 BE 或 LE 指定為編碼名稱時,BOM 只會被視為一個正常的字元(零寬度不換行空白)。
當在 decode() 過程中省略 BE 或 LE 時,它會檢查 BOM 是否在字串的開頭;如果找到一個,則位元順序會設定為 BOM 所指定的內容。
預設位元順序
當找不到 BOM 時,Encode 2.76 和 blow 會中斷。自 Encode 2.77 以來,它會根據 RFC2781 和 Unicode 標準版本 8.0 回退到 BE。
在編碼期間省略 BE 或 LE 時,它會傳回一個附加 BOM 的 BE 編碼字串。因此,當您想要編碼整個文字檔時,請務必一次編碼整個文字,而不是逐行編碼,否則每行(而非檔案)都會附加 BOM。
UCS-2
是個例外。與其他編碼不同,這是 UCS-2BE 的別名。UCS-2 已由 IANA 和其他組織以這種方式註冊。
至少可以說,代理對是 Unicode 聯盟犯下的最大錯誤。但根據已故的 Douglas Adams 在《銀河便車指南》三部曲中的說法,在開始時,宇宙被創造出來。這讓許多人非常生氣,並且被廣泛認為是一個糟糕的舉動
。他們的錯誤沒有這麼嚴重,所以讓我們原諒他們。
(我不敢拿 Unicode 聯盟和福根人做任何比較 ;) 或者,將編碼比喻成巴別魚是完全恰當的——如果你只能把它塞進你的耳朵 :))
當 Unicode 聯盟最終承認 16 位元不足以容納世界上所有的字元庫時,代理對就誕生了。但他們已經將 UCS-2 定義為 16 位元。我們該怎麼辦?
當時,0xD800-0xDFFF 範圍尚未分配。讓我們將該範圍一分為二,並使用前半部分表示字元的後半部分
,使用後半部分表示字元的前半部分
。這樣,您可以表示 1024 * 1024 = 1048576 個以上的字元。現在,即使使用 16 位元編碼,我們也可以儲存高達 \x{10ffff} 的字元範圍。這對半字元現在稱為代理對,而 UTF-16 是包含它們的編碼名稱。
以下是一個公式,用於將 Unicode 字元 \x{10000} 及以上編入代理對;
$hi = ($uni - 0x10000) / 0x400 + 0xD800;
$lo = ($uni - 0x10000) % 0x400 + 0xDC00;
並將代理對解碼;
$uni = 0x10000 + ($hi - 0xD800) * 0x400 + ($lo - 0xDC00);
請注意,此舉動已將 \x{D800}-\x{DFFF} 變成一個禁區,但 perl 並不禁止使用此範圍內的字元。對 perl 而言,從 \x{0000_0000} 到 \x{ffff_ffff} (*) 的每個字元都是一個字元。
(*) or \x{ffff_ffff_ffff_ffff} if your perl is compiled with 64-bit
integer support!
與大多數接受各種錯誤處理方式的編碼不同,Unicode 編碼只會崩潰。
% perl -MEncode -e'$_ = "\xfe\xff\xd8\xd9\xda\xdb\0\n"' \
-e'Encode::from_to($_, "utf16","shift_jis", 0); print'
UTF-16:Malformed LO surrogate d8d9 at /path/to/Encode.pm line 184.
% perl -MEncode -e'$a = "BOM missing"' \
-e' Encode::from_to($a, "utf16", "shift_jis", 0); print'
UTF-16:Unrecognised BOM 424f at /path/to/Encode.pm line 184.
與其他編碼(其對應關係並非對 Unicode 的一對一)不同,UTF 預計會彼此 100% 對應。因此,編碼對 UTF 更加嚴格。
考慮「零除」的 Encode :)
Encode、Encode::Unicode::UTF7、https://www.unicode.org/glossary/、https://www.unicode.org/faq/utf_bom.html、
RFC 2781 http://www.ietf.org/rfc/rfc2781.txt、
完整的 Unicode 標準 https://www.unicode.org/standard/standard.html
Tom Christiansen、brian d foy 和 Larry Wall 合著的《Programming Perl(第 3 版)》第 6 章,第 275 頁;O'Reilly & Associates;ISBN 978-0-596-00492-7