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) 并对其进行反代理
以形成一个字符。无效代理会导致崩溃。如果在 encode() 期间遇到 \x{10000} 或以上,它会对其进行代理
并将代理对推送到输出流。
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。
如果在 encode() 期间省略了 BE 或 LE,它会返回一个预先添加了 BOM 的 BE 编码字符串。因此,当您想对整个文本文件进行编码时,请确保一次对整个文本进行 encode(),而不是逐行或每行,而不是文件,都会预先添加 BOM。
UCS-2
是个例外。与其他编码不同,它是 UCS-2BE 的别名。UCS-2 已由 IANA 和其他机构以这种方式注册。
委婉地说,代理对是 Unicode 联盟犯下的最大错误。但根据已故道格拉斯·亚当斯在《银河系搭车客指南》三部曲中的说法,在太初,宇宙被创造出来。这让很多人非常愤怒,并被广泛认为是一个糟糕的举动
。他们的错误没有这么严重,所以让我们原谅他们吧。
(我不敢在这里将 Unicode 联盟与沃贡人相提并论 ;) 或者,将 Encode 与巴别鱼相比较完全合适——如果你能把它塞进你的耳朵的话 :)
当 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.
与映射不是一对一的其他编码不同,UTF 应该相互映射 100%。因此,Encode 对 UTF 更加严格。
考虑 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 编著的《Perl 编程(第 3 版)》第 6 章,第 275 页;O'Reilly & Associates;ISBN 978-0-596-00492-7