Encode::Encoding - Encode 实现基类
package Encode::MyEncoding;
use parent qw(Encode::Encoding);
__PACKAGE__->Define(qw(myCanonical myAlias));
如 Encode 中所述,编码(至少在当前实现中)被定义为对象。编码名称到对象的映射是通过 %Encode::Encoding
哈希表进行的。虽然您可以直接操作此哈希表,但强烈建议您使用此基类模块并添加 encode() 和 decode() 方法。
强烈建议您至少实现以下方法中的一个:encode() 或 decode()。
必须返回表示 $string 的字节序列。
如果 $check 为真,它 SHOULD 在原地修改 $string 以移除已转换的部分(即整个字符串,除非出现错误)。如果 perlio_ok() 为真,SHOULD 变成 MUST。
如果发生错误,它 SHOULD 返回已转换的字符串片段的八位字节序列,并在原地修改 $string 以移除已转换的部分,使其从问题片段开始。如果 perlio_ok() 为真,SHOULD 变成 MUST。
如果 $check 为假,则 encode
MUST 尽力转换字符串 - 例如,使用替换字符。
MUST 返回 $octets 所表示的字符串。
如果 $check 为真,它 SHOULD 在原地修改 $octets 以移除已转换的部分(即整个序列,除非出现错误)。如果 perlio_ok() 为真,SHOULD 变成 MUST。
如果发生错误,它 SHOULD 返回已转换的字符串片段,并在原地修改 $octets 以移除已转换的部分,使其从问题片段开始。如果 perlio_ok() 为真,SHOULD 变成 MUST。
如果 $check 为假,则 decode
应该尽力转换字符串 - 例如,使用 Unicode 的 "\x{FFFD}" 作为替换字符。
如果您希望您的编码与 encoding pragma 一起使用,您还应该实现下面的方法。
MUST 使用 $offset 解码 $octets 并将其连接到 $destination。解码将在 $terminator(一个字符串)出现在输出时终止。$offset 将被修改为解码结束时最后一个 $octets 的位置。如果 $terminator 出现在输出中,则返回 true,否则返回 false。
除非必须,否则您不必覆盖下面显示的方法。
预定义为
sub name { return shift->{'Name'} }
MUST 返回表示编码规范名称的字符串。
预定义为
sub mime_name{
return Encode::MIME::Name::get_mime_name(shift->name);
}
MUST 返回表示编码的 IANA 字符集名称的字符串。
预定义为
sub renew {
my $self = shift;
my $clone = bless { %$self } => ref($self);
$clone->{renewed}++;
return $clone;
}
此方法在必要时重建编码对象。如果您需要在编码期间存储状态,则在此处克隆您的对象。
PerlIO 始终调用此方法以确保它拥有自己的私有编码对象。
预定义为
sub renewed { $_[0]->{renewed} || 0 }
指示对象是否已更新(以及更新了多少次)。某些模块在值不是数字时会发出 Use of uninitialized value in null operation
警告,因此对于 false 返回 0。
预定义为
sub perlio_ok {
return eval { require PerlIO::encoding } ? 1 : 0;
}
如果您的编码由于某些原因不支持 PerlIO,只需;
sub perlio_ok { 0 }
预定义为
sub needs_lines { 0 };
如果您的编码可以与 PerlIO 一起使用,但需要行缓冲,则必须定义此方法以使其返回 true。7 位 ISO-2022 编码就是一个需要此方法的示例。当此方法缺失时,假定为 false。
package Encode::ROT13;
use strict;
use parent qw(Encode::Encoding);
__PACKAGE__->Define('rot13');
sub encode($$;$){
my ($obj, $str, $chk) = @_;
$str =~ tr/A-Za-z/N-ZA-Mn-za-m/;
$_[1] = '' if $chk; # this is what in-place edit means
return $str;
}
# Jr pna or ynml yvxr guvf;
*decode = \&encode;
1;
需要注意的是,$check 的行为与外部公共 API 不同。“未检查”情况在编码是可能报告错误的流的一部分时很有用(例如 STDERR)。在这种情况下,最好以某种方式获取所有内容,而不会导致额外的错误,这些错误会掩盖原始错误。此外,编码最适合知道正确的替换字符是什么,因此,如果这是所需的行为,那么让低级代码执行它是最有效的。
相反,如果 $check 为 true,则上述方案允许编码尽其所能,并告诉上一层它做了多少。目前缺少的是报告错误发生情况的机制。最可能的接口是对对象的额外方法调用,或者可能是(为了避免在无状态编码上强制执行每个流对象)额外的参数。
编码类从 Encode::Encoding
继承作为基类也是非常可取的。这允许该类为所有编码对象定义额外的行为。
package Encode::MyEncoding;
use parent qw(Encode::Encoding);
__PACKAGE__->Define(qw(myCanonical myAlias));
使用 bless {Name => ...}, $class
创建对象,并调用 define_encoding。它们从 Encode::Encoding
继承 name
方法。
为了速度和效率,大多数编码现在通过编译形式支持:从 UCM 文件生成的 XS 模块。Encode 提供了 enc2xs 工具来实现这一点。有关更多详细信息,请参阅 enc2xs。