decode_utf8
と encode_utf8
って何?perlunifaq - Perl Unicode FAQ
これは、perlunitut の後で読むことを想定した、Perl での Unicode に関する 質問と答えの一覧です。
はい、違います; そしてこれは実際には Unicode FAQ ではありません。
Perl は対応している全ての文字エンコーディングへの抽象インターフェースを 持っているので、実際には汎用の Encode
チュートリアルと Encode
FAQ です。 しかし、多くの人々が、Unicode は特別でマジカルなものだと考えていて、 私は彼らを失望させたくなかったので、そのドキュメントを Unicode チュートリアルと呼ぶことに決めました。
Perl がどの文字エンコーディングに対応しているかを見つけるには、以下を 実行してください:
perl -MEncode -le "print for Encode->encodings(':all')"
うーん、もし可能なら、最新にアップグレードしてください; 但し、確実に 5.8.1
以降にはしてください。 チュートリアルと FAQ は最新リリースを仮定しています。
モジュールもチェックして、もし必要ならアップグレードするべきです。 例えば HTML::Entities は、changelog は何も触れていませんが、正しく 動作するためにはバージョン >= 1.32 が必要です。
うーん、生の binmode $fh
を別として、特別に扱う必要はないはずです。 (Win32 システムで Perl が行端を変更しないようにするために、binmode が 必要です。)
但し、決してテキスト文字列とバイナリ文字列を結合しないように 注意してください。 もしバイナリストリームにテキストが必要なら、まずテキスト文字列を適切な エンコーディングを使ってエンコードして、それをバイナリ文字列と 結合してください。 "What if I don't encode?" も参照してください。
データベース、テキストファイル、ソケット、他のプログラムといった、自分の perl プロセスの外側にある何かとテキストを通信するときはいつでも、です。 通信の相手が Perl で書かれている場合も同じです。
エンコードされたバイナリ文字列をテキスト文字列と一緒に使ったときはいつでも、 Perl はバイナリ文字列が ISO-8859-1 またの名を latin-1 と仮定します。 もしこれが latin-1 でなかった場合、データは不愉快な形に変換されます。 例えば、もしデータが UTF-8 だった場合、マルチバイト文字のそれぞれのバイトが 文字として扱われ、それから再び UTF-8 に変換されます。 このような二重エンコードは二重 HTML エンコーディング (>
) や 二重 URI エンコーディング (%253E
) と比較できます。
この、暗黙のうちに行われるデコードは「昇格」("upgrading")と呼ばれます。 これは前向きなことに聞こえるかもしれませんが、避けるのが最良です。
テキスト文字列は Perl の内部形式のバイト列を使って送信されます。 いくつかの場合では、Perl は何かが間違っていることを、親切なメッセージで 警告します:
Wide character in print at example.pl line 2.
内部形式はしばしば UTF-8 なので、このバグは発見しにくいです; なぜなら あなたがほしいのは普通 UTF-8 だからです! しかし、手を抜かないでください; そして Perl の内部形式が UTF-8 であることを 利用しようとしないでください。 奇妙なバグを防ぐため、そして保守プログラマに対してあなたが何を考えたかを 示すために、明示的にエンコードしてください。
もし、あるハンドルから来る全てのデータが正確に同じ方法で エンコードされているなら、encoding
層を使って、 PerlIO システムに自動的に 全てをデコードするように伝えることができます。 これを行えば、この層のハンドルを使っている限り、うっかりデコードや エンコードを忘れることはありません。
ファイルを open
するときにこの層を指定することができます:
open my $fh, '>:encoding(UTF-8)', $filename; # auto encoding on write
open my $fh, '<:encoding(UTF-8)', $filename; # auto decoding on read
あるいは既にオープンしているファイルハンドルがあるなら:
binmode $fh, ':encoding(UTF-8)';
DBI のデータベースドライバのいくつかも、エンコードとデコードを自動的に 行いますが、ときどきこれは UTF-8 エンコーディングに制限されています。
なんとかして見つけるか、もし必要なら、推測してください。 (どう推測したかをコメントとして文書化するのを忘れないでください。)
ドキュメントを web ブラウザで開いて、全ての文字があるべき形であることを 視覚的に確認できるまで文字集合や文字エンコーディングを変更する方法も あります。
エンコーディングを自動的に検出するための信頼性のある方法はないので、 もし人々があなたに文字集合の指示なしにデータを送り続けるなら、彼らを 教育する必要があるかもしれません。
はい、できます! ソースコードが UTF-8 でエンコードされているなら、use utf8
プラグマを 使ってそれを示すことができます。
use utf8;
これは入出力に対しては何も行いません。 ソースを読み込む方法のみに影響を与えます。 文字列リテラル、識別子(しかし \w
に従った「単語文字」である必要が あります)、そして独自デリミタにすら Unicode が使えます。
いいえ、Data::Dumper の Unicode 能力は、あるべき形であります。 eval
で再びデータを読み込むとき、UTF8 フラグを復元するべきだという 苦情が来ることがあります。 しかし、実際にはフラグを見るべきではないですし、Data::Dumper がこの規則を 破っていることを示すものは何もありません。
起きているのは以下のようなことです: Perl が文字列リテラルを読み込むとき、 可能な限り長く 8 ビットエンコーディングにこだわります。 (しかしおそらく、これをダンプしたときには内部では UTF-8 でエンコード されていました。) それ以外の文字をテキスト文字列に追加するためにこれを諦めなければならない とき、Perl は暗黙のうちに文字列を UTF-8 に昇格させます。
出力用の文字列を適切にエンコードしていれば、これについてあなたは何も 心配することはなく、いつも通りにダンプしたデータを eval
できます。
Perl 5.14 から (そして部分的に Perl 5.12 から、) 単にプログラムの先頭付近に use feature 'unicode_strings'
を書いてください。 このレキシカルスコープ内ではこの問題は発生しないはずです。 これはまた use feature ':5.12'
が有効か、Perl 5.12 以降でコマンドラインで -E
を使っていると自動的に有効になります。
これが必要な理論的根拠は、Unicode がやってくる前に動作する方法に 依存している古いプログラムを壊さないことです。 このような古いプログラムは ASCII 文字集合のみを知っているので、追加の 文字については正しく動作しないかも知れません。 Perl はプログラムが Unicode を扱えるように準備されていると仮定しますが、 文字列がそうでなかった場合、Perl は (EBCDIC プラットフォームでなければ) ASCII のみが求められていると仮定するので、非 ASCII 文字は Unicode に するべきものとして認識しません。 use feature 'unicode_strings'
は Perl に、文字が UTF-8 で エンコードされているかどうかにかかわらず全ての文字を Unicode として 扱うように知らせて、この問題を回避します。
しかし、以前の Perl であったり、この機能のスコープの外側のサブルーチンに 文字列を渡した場合、utf8::upgrade($string)
とすることでエンコーディングを UTF-8 にすることで強制的に Unicode の動作を使えます。 これは既に昇格している文字列は変更しないので、どのような文字列に対しても 安全に用いることができます。
さらなる詳細な議論については、CPAN の Unicode::Semantics を 参照してください。
それはできません。 このために UTF8 フラグを使う人もいますが、これは誤用で、Data::Dumper のように 正しく振る舞うモジュールをおかしくします。 このフラグはこの目的のためには使えません; なぜなら文字列の保管に 8 ビット エンコーディングが使われている場合 (デフォルトでは ISO-8859-1 です)、 オフだからです。
把握しておく必要があるプログラマに言えることはこれです; ごめんなさい。 これを助けるために、「ハンガリアン記法」のようなものの採用を 検討することもできます。
まず FOO でエンコードされたバイト文字列をテキスト文字列に変化し、 それからテキスト文字列を BAR エンコードされたバイト文字列に変換します:
my $text_string = decode('FOO', $foo_string);
my $bar_string = encode('BAR', $text_string);
あるいは、テキスト文字列の部分を飛ばして、あるバイナリエンコーディングから 他のものへ直接変換します:
use Encode qw(from_to);
from_to($string, 'FOO', 'BAR'); # changes contents of $string
あるいは、自動でデコードとエンコードをさせることで全ての作業を行います:
open my $foofh, '<:encoding(FOO)', 'example.foo.txt';
open my $barfh, '>:encoding(BAR)', 'example.bar.txt';
print { $barfh } $_ while <$foofh>;
decode_utf8
と encode_utf8
って何?これらは decode('utf8', ...)
および encode('utf8', ...)
のもう一つの 文法です。
これは文脈に依存して、127 より大きい序数を持つ文字、255 より大きい序数を 持つ文字、1 バイトで収まらない文字、のいずれかの意味で使われる用語です。
Perl の警告 "Wide character in ..." は 255 より大きい序数を持つ文字によって 引き起こされます。 エンコーディング層が指定されていない場合、Perl は過去互換性の理由によって 文字を ISO-8859-1 に合わせようとします。 これができないと、(警告が有効なら)この警告が出力され、代わりに UTF-8 で エンコードされたデータが出力されます。
この警告を回避し、一つのストリームに異なった出力エンコーディングが 出力されることを回避するには、常に明示的にエンコーディングを指定してください; 例えば PerlIO 層を使って:
binmode STDOUT, ":encoding(UTF-8)";
内部をハックしようとしているか、変なものをデバッグしようとしているのでない 限り、どうか UTF8 フラグのことは一切考えないでください。 これは、まず間違いなく is_utf8
, _utf8_on
, _utf8_off
を 一切使うべきでないことを意味します。
UTF8 フラグ(SvUTF8 とも呼ばれます)は、現在の内部表現が UTF-8 であることを 示す内部フラグです。 このフラグがない場合、ISO-8859-1 と仮定します。 Perl はこれらを自動的に変換します。 (実際のところ Perl は普通表現が ASCII であると仮定します; 上述の "Why do regex character classes sometimes match only in the ASCII range?" を 参照してください。)
Perl の内部表現の一つはたまたま UTF-8 です。 残念ながら、Perl は秘密を守れないので、このことはみんな知っています。 これが多くの混乱の源です。 内部表現は何か分からないエンコーディングで、常に明示的にエンコードと デコードが必要ということにしておいた方がよいです。
use bytes
プラグマって何?これは使わないでください。 テキスト文字列をバイト単位で扱うことに意味はありませんし、 バイト文字列を文字単位で扱うことには意味はありません。 適切な変換(デコードかエンコード)を行えば、物事はうまくいきます: デコードしたデータの文字数を得られますし、エンコードしたデータのバイト数を 得られます。
use bytes
は何か有用なことをしようとするためには間違った方法です。 これのことは単に忘れてください。
use encoding
プラグマって何?これは使わないでください。 残念ながら、これはプログラマの環境とユーザーの環境が同じであると仮定します。 これはソースコードと STDIN や STDOUT で同じエンコーディングを使います。 プログラムが他のマシンにコピーされると、ソースコードは変わりませんが、 STDIO 環境は変わるかもしれません。
もしソースコードに非 ASCII 文字が必要なら、ファイルを UTF-8 で エンコードして、use utf8
を使ってください。
もし STDIN, STDOUT, STDERR のエンコーディングを、例えばユーザーのロケールに 合わせてセットする必要があるなら、use open
してください。
:encoding
と :utf8
の違いは?UTF-8 は Perl の内部形式のひとつなので、しばしばエンコードやデコードの 手順を省略して、UTF8 フラグを直接操作できます。
:encoding(UTF-8)
の代わりに単に :utf8
を使うことで、もしデータが 内部で既に UTF8 で表現されていれば、エンコードの手順を省略します。 これは、書き込むときにはよい振る舞いであると広く受け入れられていますが、 読み込むときには危険があります; なぜなら不正なバイト列を受け取ると 内部矛盾を引き起こすからです。 入力に :utf8
を使うとセキュリティ侵害を引き起こす可能性があるので、 どうか代わりに :encoding(UTF-8)
を使ってください。
decode
と encode
の代わりに、_utf8_on
と _utf8_off
を 使えますが、これは悪いスタイルと考えられています。 特に _utf8_on
は、:utf8
と同じ理由で危険です。
一行野郎のための省略形があります; perlrun の -C を参照してください。
UTF-8
と utf8
の違いは?UTF-8
は公式な標準です。 utf8
は、何を受け入れるかに関して自由な Perl のやり方です。 もしそれほど自由でないものと対話する必要があるなら、 UTF-8
を使うことを考えたくなるかもしれません。 自由すぎるものと対話する必要があるなら、utf8
を 使わなければならないかもしれません。 完全な説明は Encode にあります。
UTF-8
は内部では utf-8-strict
として知られます。 チュートリアルでは、たとえ内部では実際には utf8 が使われる場合でも 一貫して UTF-8 を使っています; なぜなら区別をつけるのは難しく、ほとんど 無意味だからです。
例えば utf8 は、9999999 のような、Unicode に存在しない符号位置も使えますが、 これを UTF-8 でエンコードすると、代替文字を得ることになります(これは デフォルトの場合です; これを扱う他の方法については "Handling Malformed Data" in Encode を参照してください。)
わかりました、どうしてもと言うのなら:「内部形式」は utf8 であって、 UTF-8 ではありません。 (もしその他のエンコーディングでないのなら。)
迷子になったのはよいことです; なぜなら内部形式が特定のエンコーディングで あることに依存するべきではないからです。 しかし聞かれたので答えましょう: デフォルトでは、内部形式は ISO-8859-1 (latin-1) か utf8 で、どちらになるかは文字列の歴史に 依存します。 EBCDIC プラットフォームでは、これは異なっているかもしれません。
Perl は文字列が内部でどのように保管されているかを知っていて、この知識を エンコードする
ときに使います。 言い換えると: 特定の文字列の内部エンコーディングが何かを 調べようとしてはいけません; 代わりに、単に望みのエンコーディングに エンコードしてください。
Juerd Waalboer <#####@juerd.nl>