内容

名称

Encode - Perl 中的字符编码

概要

use Encode qw(decode encode);
$characters = decode('UTF-8', $octets,     Encode::FB_CROAK);
$octets     = encode('UTF-8', $characters, Encode::FB_CROAK);

目录

Encode 包含多个模块,其细节过于庞大,无法在一份文档中全部涵盖。这份文档仅概述了顶级 API 和一般主题。有关其他主题和更多详细信息,请参阅这些模块的文档。

Encode::Alias - 编码别名定义
Encode::Encoding - 编码实现基类
Encode::Supported - 支持的编码列表
Encode::CN - 简体中文编码
Encode::JP - 日语编码
Encode::KR - 韩语编码
Encode::TW - 繁体中文编码

描述

Encode 模块提供了 Perl 字符串与系统其他部分之间的接口。Perl 字符串是由字符组成的序列。

Perl 可以表示的字符集是 Unicode 联盟定义的字符集的超集。在大多数平台上,由 ord(S) 返回的字符的序数值是该字符的Unicode 码点。例外情况是平台的传统编码是 EBCDIC 的某些变体,而不是 ASCII 的超集;请参阅 perlebcdic

在最近的历史中,数据在计算机中以 8 位块的形式移动,通常称为“字节”,但在标准文档中也称为“八位字节”。Perl 被广泛用于操作各种类型的数据:不仅是表示人类或计算机语言的字符字符串,还有“二进制”数据,即机器对数字、图像中的像素或几乎所有事物的表示。

当 Perl 处理“二进制数据”时,程序员希望 Perl 处理“字节序列”。这对 Perl 来说不是问题:因为一个字节有 256 个可能的值,它很容易适合 Perl 更大的“逻辑字符”。

本文档主要解释了如何perlunitutperlunifaq 解释了为什么

术语

字符

范围为 0 .. 2**32-1(或更大)的字符;Perl 字符串的组成部分。

byte

0..255 范围内的字符;Perl 字符的一种特殊情况。

octet

8 位数据,序数值为 0..255;用于传递给非 Perl 上下文或从非 Perl 上下文接收的字节,例如磁盘文件、标准 I/O 流、数据库、命令行参数、环境变量、套接字等。

PERL 编码 API

基本方法

encode

$octets  = encode(ENCODING, STRING[, CHECK])

将标量值 STRING 从 Perl 的内部形式编码为 ENCODING,并返回一系列字节。ENCODING 可以是规范名称或别名。有关编码名称和别名,请参见 "定义别名"。有关 CHECK,请参见 "处理格式错误的数据"

警告:输入标量 STRING 可能会根据 CHECK 中设置的内容在原地修改。如果您希望输入保持不变,请参见 "LEAVE_SRC"

例如,要将字符串从 Perl 的内部格式转换为 ISO-8859-1,也称为 Latin1

$octets = encode("iso-8859-1", $string);

警告:当您运行 $octets = encode("UTF-8", $string) 时,$octets 可能不等于 $string。尽管两者都包含相同的数据,但 $octets 的 UTF8 标志始终为关闭。当您对任何内容进行编码时,结果上的 UTF8 标志始终为关闭,即使它包含完全有效的 UTF-8 字符串。请参见下面的 "UTF8 标志"

如果 $string 为 undef,则返回 undef

str2bytes 可用作 encode 的别名。

decode

$string = decode(ENCODING, OCTETS[, CHECK])

此函数返回将标量值 OCTETS(假设为 ENCODING 中的一系列字节)解码为 Perl 的内部形式后得到的字符串。与 encode() 一样,ENCODING 可以是规范名称或别名。有关编码名称和别名,请参见 "定义别名";有关 CHECK,请参见 "处理格式错误的数据"

警告:输入标量 OCTETS 可能会根据 CHECK 中设置的内容在原地修改。如果您希望输入保持不变,请参见 "LEAVE_SRC"

例如,要将 ISO-8859-1 数据转换为 Perl 的内部格式的字符串

$string = decode("iso-8859-1", $octets);

警告:当您运行 $string = decode("UTF-8", $octets) 时,$string 可能不等于 $octets。尽管两者包含相同的数据,但 $string 的 UTF8 标志已开启。请参阅下方 "UTF8 标志"

如果 $string 为 undef,则返回 undef

bytes2str 可用作 decode 的别名。

find_encoding

[$obj =] find_encoding(ENCODING)

返回与 ENCODING 对应的 编码对象。如果未找到匹配的 ENCODING,则返回 undef。返回的对象是执行实际编码或解码的对象。

$string = decode($name, $bytes);

实际上是

$string = do {
    $obj = find_encoding($name);
    croak qq(encoding "$name" not found) unless ref $obj;
    $obj->decode($bytes);
};

具有更多错误检查。

因此,您可以通过以下方式重用此对象来节省时间;

my $enc = find_encoding("iso-8859-1");
while(<>) {
    my $string = $enc->decode($_);
    ... # now do something with $string;
}

除了 "decode""encode" 之外,还提供其他方法。例如,name() 返回编码对象的规范名称。

find_encoding("latin1")->name; # iso-8859-1

有关详细信息,请参阅 Encode::Encoding

find_mime_encoding

[$obj =] find_mime_encoding(MIME_ENCODING)

返回与 MIME_ENCODING 对应的 编码对象。与 find_encoding() 的作用相同,但返回对象的 mime_name() 必须与 MIME_ENCODING 匹配。因此,与 find_encoding() 相反,在搜索对象时不使用规范名称和别名。

find_mime_encoding("utf8"); # returns undef because "utf8" is not valid I<MIME_ENCODING>
find_mime_encoding("utf-8"); # returns encode object "utf-8-strict"
find_mime_encoding("UTF-8"); # same as "utf-8" because I<MIME_ENCODING> is case insensitive
find_mime_encoding("utf-8-strict"); returns undef because "utf-8-strict" is not valid I<MIME_ENCODING>

from_to

[$length =] from_to($octets, FROM_ENC, TO_ENC [, CHECK])

在两种编码之间 就地 转换数据。$octets 中的数据必须以字节形式编码,而不是以 Perl 的内部格式编码。例如,要将 ISO-8859-1 数据转换为 Microsoft 的 CP1250 编码

from_to($octets, "iso-8859-1", "cp1250");

以及将其转换回来

from_to($octets, "cp1250", "iso-8859-1");

由于转换是在原地进行的,因此要转换的数据不能是字符串常量:它必须是标量变量。

from_to() 在成功时返回以字节为单位的已转换字符串的长度,在错误时返回 undef

警告:以下操作可能看起来相同,但实际上并非如此

from_to($data, "iso-8859-1", "UTF-8"); #1
$data = decode("iso-8859-1", $data);  #2

#1 和 #2 都使 $data 包含一个完全有效的 UTF-8 字符串,但只有 #2 打开 UTF8 标志。#1 等效于

$data = encode("UTF-8", decode("iso-8859-1", $data));

请参阅下方 "UTF8 标志"

另请注意

from_to($octets, $from, $to, $check);

等效于

$octets = encode($to, decode($from, $octets), $check);

是的,它在解码期间尊重 $check。这是故意这样做的。如果您需要精确控制,请使用 decode 后跟 encode,如下所示

$octets = encode($to, decode($from, $octets, $check_from), $check_to);

encode_utf8

$octets = encode_utf8($string);

警告此函数可能会生成无效的 UTF-8! 不要将其用于数据交换。除非您想要 Perl 的旧“宽松”模式,否则请优先使用 $octets = encode("UTF-8", $string)

等效于 $octets = encode("utf8", $string)。$string 中的字符以 Perl 的内部格式编码,结果以字节序列的形式返回。由于 Perl 中所有可能的字符都有一个(宽松的,而不是严格的)utf8 表示,因此此函数不会失败。

decode_utf8

$string = decode_utf8($octets [, CHECK]);

警告此函数接受无效的 UTF-8! 不要将其用于数据交换。除非您想要 Perl 的旧“宽松”模式,否则请优先使用 $string = decode("UTF-8", $octets [, CHECK])

等效于 $string = decode("utf8", $octets [, CHECK])。$octets 表示的字节序列从(宽松的,而不是严格的)utf8 解码为逻辑字符序列。由于并非所有字节序列都是有效的非严格 utf8,因此此函数很可能失败。有关 CHECK,请参阅 "处理格式错误的数据"

警告:输入$octets可能会根据CHECK中的设置在内存中被修改。如果您希望输入保持不变,请参见"LEAVE_SRC"

列出可用的编码

use Encode;
@list = Encode->encodings();

返回已加载的可用编码的规范名称列表。要获取所有可用编码的列表,包括尚未加载的编码,请说

@all_encodings = Encode->encodings(":all");

或者您可以给出特定模块的名称

@with_jp = Encode->encodings("Encode::JP");

当名称中没有"::"时,将假定为"Encode::"。

@ebcdic = Encode->encodings("EBCDIC");

要详细了解此包支持哪些编码,请参见Encode::Supported

定义别名

要为给定编码添加新别名,请使用

use Encode;
use Encode::Alias;
define_alias(NEWNAME => ENCODING);

之后,NEWNAME可以用作ENCODING的别名。ENCODING可以是编码的名称或编码对象

在执行此操作之前,请首先使用resolve_alias()确保别名不存在,该函数返回其规范名称。例如

Encode::resolve_alias("latin1") eq "iso-8859-1" # true
Encode::resolve_alias("iso-8859-12")   # false; nonexistent
Encode::resolve_alias($name) eq $name  # true if $name is canonical

resolve_alias()不需要use Encode::Alias;它可以通过use Encode qw(resolve_alias)导入。

有关详细信息,请参见Encode::Alias

查找IANA字符集注册表名称

给定编码的规范名称不一定与IANA字符集注册表一致,通常称为Content-Type: text/plain; charset=WHATEVER。在大多数情况下,规范名称有效,但有时无效,最显著的是"utf-8-strict"。

Encode版本2.21开始,因此添加了新方法mime_name()

use Encode;
my $enc = find_encoding("UTF-8");
warn $enc->name;      # utf-8-strict
warn $enc->mime_name; # UTF-8

另请参见:Encode::Encoding

通过PerlIO进行编码

如果您的perl支持PerlIO(这是默认设置),您可以使用PerlIO层通过文件句柄直接解码和编码。以下两个示例在功能上完全相同

### Version 1 via PerlIO
  open(INPUT,  "< :encoding(shiftjis)", $infile)
      || die "Can't open < $infile for reading: $!";
  open(OUTPUT, "> :encoding(euc-jp)",  $outfile)
      || die "Can't open > $output for writing: $!";
  while (<INPUT>) {   # auto decodes $_
      print OUTPUT;   # auto encodes $_
  }
  close(INPUT)   || die "can't close $infile: $!";
  close(OUTPUT)  || die "can't close $outfile: $!";

### Version 2 via from_to()
  open(INPUT,  "< :raw", $infile)
      || die "Can't open < $infile for reading: $!";
  open(OUTPUT, "> :raw",  $outfile)
      || die "Can't open > $output for writing: $!";

  while (<INPUT>) {
      from_to($_, "shiftjis", "euc-jp", 1);  # switch encoding
      print OUTPUT;   # emit raw (but properly encoded) data
  }
  close(INPUT)   || die "can't close $infile: $!";
  close(OUTPUT)  || die "can't close $outfile: $!";

在上面的第一个版本中,您让相应的编码层处理转换。在第二个版本中,您明确地从一种编码转换为另一种编码。

不幸的是,编码可能不支持PerlIO。您可以通过调用其上的perlio_ok方法来检查您的编码是否受PerlIO支持

Encode::perlio_ok("hz");             # false
find_encoding("euc-cn")->perlio_ok;  # true wherever PerlIO is available

use Encode qw(perlio_ok);            # imported upon request
perlio_ok("euc-jp")

幸运的是,除了hzISO-2022-kr之外,所有随Encode核心提供的编码都支持PerlIO。有关详细信息,请参见Encode::EncodingEncode::PerlIO

处理格式错误的数据

可选的 CHECK 参数告诉 Encode 在遇到格式错误的数据时该怎么做。如果没有 CHECK,则假定为 Encode::FB_DEFAULT (== 0)。

从 2.12 版本开始,Encode 支持 CHECK 的代码引用值;请参见下文。

注意:并非所有编码都支持此功能。某些编码会忽略 CHECK 参数。例如,Encode::Unicode 会忽略 CHECK,并且它始终在错误时报错。

CHECK 值列表

FB_DEFAULT

I<CHECK> = Encode::FB_DEFAULT ( == 0)

如果 CHECK 为 0,则编码和解码会将任何格式错误的字符替换为 替换字符。编码时,使用 SUBCHAR。解码时,使用 Unicode 替换字符,代码点 U+FFFD。如果数据应该是 UTF-8,则会发出可选的词法警告,警告类别为 "utf8"

FB_CROAK

I<CHECK> = Encode::FB_CROAK ( == 1)

如果 CHECK 为 1,则方法会立即以错误消息终止。因此,当 CHECK 为 1 时,您应该使用 eval{} 捕获异常,除非您确实希望它 die

FB_QUIET

I<CHECK> = Encode::FB_QUIET

如果 CHECK 设置为 Encode::FB_QUIET,则编码和解码在发生错误时会立即返回已处理数据的部分。数据参数将被覆盖为该点之后的所有内容;也就是说,未处理的数据部分。当您必须在源数据可能包含部分多字节字符序列的情况下重复调用 decode 时,这很方便(也就是说,您正在使用固定宽度缓冲区读取)。以下是一些执行此操作的示例代码

my($buffer, $string) = ("", "");
while (read($fh, $buffer, 256, length($buffer))) {
    $string .= decode($encoding, $buffer, Encode::FB_QUIET);
    # $buffer now contains the unprocessed partial character
}

FB_WARN

I<CHECK> = Encode::FB_WARN

这与上面的 FB_QUIET 相同,只是它不会在错误时保持沉默,而是会发出警告。这在调试时很方便。

警告:Encode 模块的所有警告都会被报告,与 pragma warnings 设置无关。如果您想遵循由 pragma warnings 配置的词法警告设置,那么也附加检查值 ENCODE::ONLY_PRAGMA_WARNINGS。此值从 Encode 2.99 版本开始可用。

FB_PERLQQ FB_HTMLCREF FB_XMLCREF

perlqq 模式 (CHECK = Encode::FB_PERLQQ)
HTML 字符引用模式 (CHECK = Encode::FB_HTMLCREF)
XML 字符引用模式 (CHECK = Encode::FB_XMLCREF)

对于由 Encode::XS 模块实现的编码,CHECK == Encode::FB_PERLQQencodedecode 置于 perlqq 回退模式。

解码时,对于无法解码为 utf8 的字节,会插入 \xHH,其中 HH 是该字节的十六进制表示。编码时,会插入 \x{HHHH},其中 HHHH 是无法在编码字符集中找到的字符的 Unicode 代码点(以任意数量的十六进制数字表示)。

HTML/XML 字符引用模式大致相同。代替 \x{HHHH},HTML 使用 &#NNN;,其中 NNN 是十进制数,而 XML 使用 &#xHHHH;,其中 HHHH 是十六进制数。

Encode 2.10 或更高版本中,LEAVE_SRC 也被隐式包含。

位掩码

这些模式实际上都是通过位掩码设置的。以下是 FB_XXX 常量的布局方式。您可以通过 use Encode qw(:fallbacks) 导入 FB_XXX 常量,也可以通过 use Encode qw(:fallback_all) 导入通用位掩码常量。

                    FB_DEFAULT FB_CROAK FB_QUIET FB_WARN  FB_PERLQQ
DIE_ON_ERR    0x0001             X
WARN_ON_ERR   0x0002                               X
RETURN_ON_ERR 0x0004                      X        X
LEAVE_SRC     0x0008                                        X
PERLQQ        0x0100                                        X
HTMLCREF      0x0200
XMLCREF       0x0400

LEAVE_SRC

Encode::LEAVE_SRC

如果 Encode::LEAVE_SRC 位未设置但 CHECK 已设置,则将就地覆盖要编码或解码的源字符串。如果您对此不感兴趣,请将其与位掩码进行按位或运算。

CHECK 的代码引用

Encode 2.12 开始,CHECK 也可以是一个代码引用,它以未映射字符的序号值作为参数,并返回表示回退字符的字节。例如

$ascii = encode("ascii", $utf8, sub{ sprintf "<U+%04X>", shift });

类似于 FB_PERLQQ,但使用 U+XXXX 代替 \x{XXXX}

decode 的回退必须返回解码后的字符串(字符序列),并以序号值的列表作为参数。例如,如果您希望将字节解码为 UTF-8,并使用 ISO-8859-15 作为无效 UTF-8 字节的回退,您可以编写

$str = decode 'UTF-8', $octets, sub {
    my $tmp = join '', map chr, @_;
    return decode 'ISO-8859-15', $tmp;
};

定义编码

要定义新的编码,请使用

use Encode qw(define_encoding);
define_encoding($object, CANONICAL_NAME [, alias...]);

CANONICAL_NAME 将与 $object 关联。该对象应提供 Encode::Encoding 中描述的接口。如果提供了两个以上参数,则其他参数将被视为 $object 的别名。

有关详细信息,请参阅 Encode::Encoding

UTF8 标志

在 Perl 中引入 Unicode 支持之前,eq 运算符只是比较两个标量表示的字符串。从 Perl 5.8 开始,eq 同时考虑UTF8 标志来比较两个字符串。为了解释我们为什么要这样做,我引用了Programming Perl, 3rd ed. 第 402 页的内容。

目标 #1

旧的基于字节的程序不应该在它们以前使用的旧的基于字节的数据上自发地崩溃。

目标 #2

旧的基于字节的程序应该在适当的时候神奇地开始在新的基于字符的数据上工作。

目标 #3

程序在新的基于字符的模式下运行的速度应该与在旧的基于字节的模式下一样快。

目标 #4

Perl 应该保持为一种语言,而不是分叉成一个基于字节的 Perl 和一个基于字符的 Perl。

Programming Perl, 3rd ed. 被编写时,甚至 Perl 5.6.0 都还没有诞生,书中记录的许多功能在很长一段时间内都没有实现。Perl 5.8 修正了其中很多问题,引入 UTF8 标志就是其中之一。你可以认为 Perl 中有两种根本不同的字符串和字符串操作:一种是当内部 UTF8 标志关闭时的基于字节的模式,另一种是当内部 UTF8 标志打开时的基于字符的模式。

这个 UTF8 标志在 Perl 脚本中不可见,原因与你不能(或者更确切地说,你不必)看到一个标量是否包含一个字符串、一个整数或一个浮点数完全相同。但你仍然可以窥视和戳它们,如果你愿意的话。参见下一节。

干预 Perl 的内部机制

以下 API 使用了当前实现中 Perl 内部机制的一部分。因此,它们效率很高,但可能会在将来的版本中发生变化。

is_utf8

is_utf8(STRING [, CHECK])

[内部] 测试STRING 中的 UTF8 标志是否打开。如果CHECK 为真,还会检查STRING 是否包含格式良好的 UTF-8。如果成功,则返回真,否则返回假。

通常只用于调试和测试。不要使用此标志来区分字符和二进制数据,这应该在编写代码时为每个变量决定。

警告:如果STRING 设置了 UTF8 标志,并不意味着STRING 是 UTF-8 编码的,反之亦然。

从 Perl 5.8.1 开始,utf8 也具有 utf8::is_utf8 函数。

_utf8_on

_utf8_on(STRING)

[内部] 将STRING的内部 UTF8 标志设置为开启STRING不会被检查是否只包含格式良好的 UTF-8。除非你绝对确定 STRING 只包含格式良好的 UTF-8,否则不要使用它。返回 UTF8 标志的先前状态(所以请不要将返回值视为成功或失败的指示),或者如果STRING不是字符串,则返回undef

注意:出于安全原因,此函数不适用于受污染的值。

_utf8_off

_utf8_off(STRING)

[内部] 将STRING的内部 UTF8 标志设置为关闭。不要随意使用。返回 UTF8 标志的先前状态,或者如果STRING不是字符串,则返回undef。不要将返回值视为成功或失败的指示,因为这不是它的含义:它只是先前的设置。

注意:出于安全原因,此函数不适用于受污染的值。

UTF-8 vs. utf8 vs. UTF8

....We now view strings not as sequences of bytes, but as sequences
of numbers in the range 0 .. 2**32-1 (or in the case of 64-bit
computers, 0 .. 2**64-1) -- Programming Perl, 3rd ed.

这在历史上一直是 Perl 对 UTF-8 的理解,因为这是 Ken Thompson 在发明 UTF-8 时最初设想的方式。然而,由于后来对相关标准的修订,官方 UTF-8 现在比以前更加严格。例如,它的范围要窄得多(0 .. 0x10_FFFF 只涵盖 21 位,而不是 32 位或 64 位),并且一些序列不允许使用,例如代理对中使用的序列、31 个非字符代码点 0xFDD0 .. 0xFDEF、任何平面中的最后两个代码点(0xXX_FFFE 和 0xXX_FFFF)、所有非最短编码等。

Perl 以前默认始终使用对 UTF-8 的宽松解释,现在已被推翻了。

From: Larry Wall <[email protected]>
Date: December 04, 2004 11:51:58 JST
To: [email protected]
Subject: Re: Make Encode.pm support the real UTF-8
Message-Id: <[email protected]>

On Fri, Dec 03, 2004 at 10:12:12PM +0000, Tim Bunce wrote:
: I've no problem with 'utf8' being perl's unrestricted uft8 encoding,
: but "UTF-8" is the name of the standard and should give the
: corresponding behaviour.

For what it's worth, that's how I've always kept them straight in my
head.

Also for what it's worth, Perl 6 will mostly default to strict but
make it easy to switch back to lax.

Larry

明白了吗?从 Perl 5.8.7 开始,"UTF-8" 指的是当前意义上的 UTF-8,它是保守的、严格的、注重安全的,而"utf8" 指的是以前意义上的 UTF-8,它是宽松的、自由的、不严格的。因此,Encode 版本 2.10 或更高版本理解了 "UTF-8""utf8" 之间的这种微妙但至关重要的区别。

encode("utf8",  "\x{FFFF_FFFF}", 1); # okay
encode("UTF-8", "\x{FFFF_FFFF}", 1); # croaks

这种区别对于解码也很重要。在以下示例中,$s 存储字符 U+200000,它超出了 UTF-8 允许的范围。因此,$s 存储了一个无效的 Unicode 代码点。

$s = decode("utf8", "\xf8\x88\x80\x80\x80");

相反,"UTF-8" 将强制输入转换为有效的内容。

$s = decode("UTF-8", "\xf8\x88\x80\x80\x80"); # U+FFFD

.. 或者报错。

decode("UTF-8", "\xf8\x88\x80\x80\x80", FB_CROAK|LEAVE_SRC);

Encode 模块中,"UTF-8" 实际上是 "utf-8-strict" 的规范名称。"UTF""8" 之间的连字符至关重要;如果没有它,Encode 将变得“宽松”和(可能过于)宽容。

find_encoding("UTF-8")->name # is 'utf-8-strict'
find_encoding("utf-8")->name # ditto. names are case insensitive
find_encoding("utf_8")->name # ditto. "_" are treated as "-"
find_encoding("UTF8")->name  # is 'utf8'.

Perl 的内部 UTF8 标志称为“UTF8”,没有连字符。它指示字符串是否以“utf8”内部编码,同样没有连字符。

参见

Encode::EncodingEncode::SupportedEncode::PerlIOencodingperlebcdic"open" 在 perlfunc 中perlunicodeperluniintroperlunifaqperlunitut utf8,Perl Unicode 邮件列表 http://lists.perl.org/list/perl-unicode.html

维护者

该项目最初由已故的 Nick Ing-Simmons 发起,后来由 Dan Kogai <[email protected]> 维护。有关参与人员的完整列表,请参阅 AUTHORS。如有任何问题,请发送邮件至 <[email protected]>,以便我们大家分享。

虽然 Dan Kogai 保留了作为维护者的版权,但应将功劳归于所有参与者。有关向该项目提交代码的人员列表,请参阅 AUTHORS。

版权

版权所有 2002-2014 Dan Kogai <[email protected]>

该库是免费软件;您可以在与 Perl 本身相同的条款下重新分发和/或修改它。