内容

名称

Encode::Unicode -- 各种 Unicode 转换格式

概要

use Encode qw/encode decode/;
$ucs2 = encode("UCS-2BE", $utf8);
$utf8 = decode("UCS-2BE", $ucs2);

摘要

此模块实现了 Unicode 联盟正式记录的所有 Unicode 字符编码方案(当然,除了 UTF-8,这是 perl 中的本机格式)。

http://www.unicode.org/glossary/

字符编码方案 字符编码形式加上字节序列化。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
---------------+-----------------+------------------------------

大小、字节序和 BOM

您可以通过 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})。

以网络字节序获取时 BOM 作为整数
            16         32 bits/char
-------------------------
BE      0xFeFF 0x0000FeFF
LE      0xFFFe 0xFFFe0000
-------------------------

此模块处理 BOM 的方式如下。

代理对

委婉地说,代理对是 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::UTF7https://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