目錄

名稱

Encode::Encoding - Encode 實作基礎類別

語法

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

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

說明

Encode 中所述,編碼(至少在目前的實作中)定義為物件。編碼名稱與物件的對應是透過 %Encode::Encoding hash。雖然您可以直接操作此 hash,但強烈建議使用此基礎類別模組並新增 encode() 和 decode() 方法。

您應該實作的方法

強烈建議您實作以下方法,至少 encode() 或 decode() 之一。

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

必須傳回代表 $string 的八位元組序列。

  • 如果 $check 為真,它應修改 $string 以移除已轉換的部分(即整個字串,除非有錯誤)。如果 perlio_ok() 為真,應修改為必須修改。

  • 如果發生錯誤,它應傳回已轉換字串片段的八位元組序列,並修改 $string 以移除已轉換的部分,使其從問題片段開始。如果 perlio_ok() 為真,應修改為必須修改。

  • 如果 $check 為假,則 encode 必須盡力轉換字串,例如使用替換字元。

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

必須傳回 $octets 所代表的字串。

  • 如果 $check 為真,它應修改 $octets 以移除已轉換的部分(即整個序列,除非有錯誤)。如果 perlio_ok() 為真,應修改為必須修改。

  • 如果發生錯誤,它應傳回已轉換的字串片段,並修改 $octets 以移除已轉換的部分,使其從問題片段開始。如果 perlio_ok() 為真,應修改為必須修改。

  • 如果 $check 為假,則 decode 應盡力轉換字串,例如使用 Unicode 的「\x{FFFD}」作為替換字元。

如果您希望編碼與 編碼 實用程式一起使用,您還應實作以下方法。

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

必須使用 $offset 解碼 $octets,並將其串接至 $destination。當 $terminator(一個字串)出現在輸出中時,解碼將會終止。$offset 將會修改為解碼結束時 $octets 的最後位置。如果 $terminator 出現在輸出中,則傳回 true,否則傳回 false。

Encode::Encodings 中定義的其他方法

除非必要,否則您不必覆寫以下顯示的方法。

->name

預定義為

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

必須傳回代表編碼標準名稱的字串。

->mime_name

預定義為

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

必須傳回代表編碼的 IANA 字元集名稱的字串。

->renew

預定義為

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

此方法會在必要時重建編碼物件。如果您需要在編碼期間儲存狀態,可以在這裡複製您的物件。

PerlIO 永遠會呼叫此方法,以確保它有自己的私人編碼物件。

->renewed

預定義為

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

表示物件是否已更新(以及更新幾次)。某些模組會發出「在空運算中使用未初始化值」警告,除非值是數字,因此對於 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。7bit 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 以取得更多詳細資料。

另請參閱

perlmodenc2xs