内容

名称

Encode::Encoding - Encode 实现基类

概要

package Encode::MyEncoding;
use parent qw(Encode::Encoding);

__PACKAGE__->Define(qw(myCanonical myAlias));

描述

Encode 中所述,编码(至少在当前实现中)被定义为对象。编码名称到对象的映射是通过 %Encode::Encoding 哈希表进行的。虽然您可以直接操作此哈希表,但强烈建议您使用此基类模块并添加 encode() 和 decode() 方法。

您应该实现的方法

强烈建议您至少实现以下方法中的一个:encode() 或 decode()。

->encode($string [,$check])

必须返回表示 $string 的字节序列。

  • 如果 $check 为真,它 SHOULD 在原地修改 $string 以移除已转换的部分(即整个字符串,除非出现错误)。如果 perlio_ok() 为真,SHOULD 变成 MUST。

  • 如果发生错误,它 SHOULD 返回已转换的字符串片段的八位字节序列,并在原地修改 $string 以移除已转换的部分,使其从问题片段开始。如果 perlio_ok() 为真,SHOULD 变成 MUST。

  • 如果 $check 为假,则 encode MUST 尽力转换字符串 - 例如,使用替换字符。

->decode($octets [,$check])

MUST 返回 $octets 所表示的字符串。

  • 如果 $check 为真,它 SHOULD 在原地修改 $octets 以移除已转换的部分(即整个序列,除非出现错误)。如果 perlio_ok() 为真,SHOULD 变成 MUST。

  • 如果发生错误,它 SHOULD 返回已转换的字符串片段,并在原地修改 $octets 以移除已转换的部分,使其从问题片段开始。如果 perlio_ok() 为真,SHOULD 变成 MUST。

  • 如果 $check 为假,则 decode 应该尽力转换字符串 - 例如,使用 Unicode 的 "\x{FFFD}" 作为替换字符。

如果您希望您的编码与 encoding pragma 一起使用,您还应该实现下面的方法。

->cat_decode($destination, $octets, $offset, $terminator [,$check])

MUST 使用 $offset 解码 $octets 并将其连接到 $destination。解码将在 $terminator(一个字符串)出现在输出时终止。$offset 将被修改为解码结束时最后一个 $octets 的位置。如果 $terminator 出现在输出中,则返回 true,否则返回 false。

在 Encode::Encodings 中定义的其他方法

除非必须,否则您不必覆盖下面显示的方法。

->name

预定义为

sub name  { return shift->{'Name'} }

MUST 返回表示编码规范名称的字符串。

->mime_name

预定义为

sub mime_name{
  return Encode::MIME::Name::get_mime_name(shift->name);
}

MUST 返回表示编码的 IANA 字符集名称的字符串。

->renew

预定义为

sub renew {
  my $self = shift;
  my $clone = bless { %$self } => ref($self);
  $clone->{renewed}++;
  return $clone;
}

此方法在必要时重建编码对象。如果您需要在编码期间存储状态,则在此处克隆您的对象。

PerlIO 始终调用此方法以确保它拥有自己的私有编码对象。

->renewed

预定义为

sub renewed { $_[0]->{renewed} || 0 }

指示对象是否已更新(以及更新了多少次)。某些模块在值不是数字时会发出 Use of uninitialized value in null operation 警告,因此对于 false 返回 0。

->perlio_ok()

预定义为

sub perlio_ok { 
  return eval { require PerlIO::encoding } ? 1 : 0;
}

如果您的编码由于某些原因不支持 PerlIO,只需;

sub perlio_ok { 0 }
->needs_lines()

预定义为

sub needs_lines { 0 };

如果您的编码可以与 PerlIO 一起使用,但需要行缓冲,则必须定义此方法以使其返回 true。7 位 ISO-2022 编码就是一个需要此方法的示例。当此方法缺失时,假定为 false。

示例:Encode::ROT13

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;

为什么 Encode API 如此不同?

需要注意的是,$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

另请参阅

perlmod, enc2xs