NAME

perluniintro - Perl Unicode の手引き

DESCRIPTION

このドキュメントは、Unicode の一般的な考えと、 Perl で Unicode をどのように使うかを書いています。

Unicode

Unicode は、文字セットの標準です。 世界の全ての書記体系と、それに加えて、 他の多くのシンボルを体系化することを計画しています。

Unicode と、ISO/IEC 10646 は、よく調整された、符号位置を提供する 標準です。 Unicode は、ほとんど全ての現代の文字セット標準、30 以上の書記体系と、 100 以上の言語を網羅します。 全ての商業的に重要な現代の言語を含みます。 もっとも大きい中国語、日本語、韓国語、それぞれの辞書の全ての文字もまた、 符号化されています。 この標準は、最終的には、250 の書記体系と、1000 以上の言語のほとんどすべての 文字を網羅する予定です。 Unicode 1.0 は、1991 年 10 月にリリースされ、Unicode 4.0 は、 2003 年 4 月にリリースされました。

Unicode の 文字 は、抽象的な存在です。 Unicode の文字は、どんな特定の整数幅にも、特に、C 言語の char にも 束縛されません。 Unicode は、言語中立で、表示中立です: Unicode は、テキストの言語をエンコードしませんし、 一般的にはフォントや他のグラフィカルなレイアウトの詳細を定義しません。 Unicode は、文字と、それらの文字からなるテキストを操作します。

Unicode は、LATIN CAPITAL LETTER AGREEK SMALL LETTER ALPHA のような 文字と、その文字について固有の番号を定義します。 この場合は、それぞれ、0x0041 と、0x03B1 になります。 このような固有の番号は、符号位置 と呼ばれます。

Unicode 標準は、符号位置に 16 進記法を使うのを好みます。 0x0041 のような番号に馴染みがなければ、後のセクション、 "Hexadecimal Notation" を覗いて見て下さい。 Unicode 標準は、U+0041 LATIN CAPITAL LETTER A という表記を使って、 16 進法の符号位置と標準的な文字の名前を書きます。

Unicode はまた、様々な文字の 性質 を定義します。 "大文字"、"小文字"、"10進数字"、"句読点" など; これらの性質は、文字の名前と独立です。 更に、様々な文字に対する操作、大文字化や小文字化や並び替えが 定義されています。

Unicode 論理 「文字」は、実際には一つ以上の 実際 の「文字」または 符号位置から構成されます。 西洋の言語では、これは (LATIN CAPITAL LETTER A のような)、基底文字 (base character) に続いて、一つ以上の(COMBINING ACUTE ACCENT のような) 修飾字 (modifiers) によってモデル化されています。、 この基底文字と修飾字の並びは、結合文字の並び (combining character sequence) と呼ばれます。 一部の非西洋言語ではより複雑なモデルが必要なので、Unicode は 書記素クラスタ (grapheme cluster) という概念を、それから 拡張書記素クラスタ (extended grapheme cluster) を作りました。 例えば、ハングル音節文字は一つの論理文字として考えられますが、とても しばしば三つの実際の Unocde 文字から構成されています: 先頭子音に引き続いて内部母音、それに引き続いて末尾子音です。

これらの拡張書記素クラスタを「複数の文字」と呼ぶかどうかは、 考え方によります。 プログラマならば、おそらく、この順番のそれぞれの要素を、 1 つの単位か "文字" として、見ようとするでしょう。 全ての順番を一つの"文字"として見ることができます。 ですが、ユーザの考え方からは、おそらくユーザの言語の文脈でみえるような ものでしょう。

この、文字の"すべての順番"の見え方では、文字の総数には、制限がありません。 ですが、プログラマーの"一つの単位は一つの文字"という考え方では、"文字" の 概念は、より決定論的です。 このドキュメントでは、2 番目の考え方を取ります: 1 つの「文字」は、1 つの Unicode の符号位置です。

いくつかの組合せにとって、まだ構成されていない 文字があります。 たとえば、LATIN CAPITAL LETTER A WITH ACUTE は、 単一の符号位置として定義されています。 しかし、これらの、まだ構成されていない文字は、いくつかの組合せで 可能でしかありません。 そして、それらは、主に、Unicode と、レガシー標準(ISO 8859 のような)との 間の相互変換をサポートすることを意味します。 一般的なケースでは、構成する方法はより広がります。 違った構成間の変換をサポートするために、表現を標準化する、様々な normalization forms もまた定義されています。

レガシーエンコーディングとの後方互換性のために、 "全ての文字に固有の番号" という考えは、少々壊れています: その代わりに、"少なくとも全ての文字に 1 つの番号" があります。 同じ文字が、いくつかのレガシーエンコーディングの中で、違うように 表現されていました。 逆は真でもなく: 符号位置には、文字が割り当てられていないものも あります。 1 番目に、使われているブロック内にもかかわらず、割り当てられていない 符号位置があります。 2 番目に、特別な Unicode のコントロール文字があり、それらは、本物の文字を 表現しません。

Unicode について、よく知られている神話は、Unicode が、「16 ビット」である、 というものです。 Unicode は、0x0000 から、0xFFFF までで、0x10000 (か、65536)の 文字を表現するだけ、というものです。 これは真実ではありません。 Unicode 2.0(1996 年 7 月)から、Unicode は、21ビット(0x10FFFF)まで、 様々に定義されています。 Unicode 3.1(2001 年 3 月)から、文字は、0xFFFF を超えて、定義されました。 最初の 0x10000 文字は、 Plane 0、または、Basime Multilingual Plane(BMP)と、と呼ばれました。 Unicode 3.1 で、全部で 17(そう、17)の Plane が定義されました -- ですが、 まだ、定義された全文字のどこにも、まだ近くにありません。

もう 1 つの神話は Unicode ブロックに関するものです -- これが何か言語を 取り扱うことがある -- それぞれのブロックは言語か言語のセットで使われている文字を 定義するということです。 これもまた真実ではありません。 ブロックに分割されたものはありますが、それは、ほとんど完全に、 予想外のものです。 代わりに、用字 (scripts) と呼ばれる、より有益なコンセプトがあります: Latin 用字と、Greek 用字と、その他のものがあります。 用字は、ふつう、いくつかのブロックの変えられた部分を測っています。 詳しくは、"Scripts" in perlunicode を見て下さい。

Unicode の符号位置は、抽象的な数字です。 この抽象的な数字を入出力するために、数字は、エンコードされる 必要が あるか、シリアライズされる か、どうか、しなければなりません。 Unicode は、複数の character encoding forms を定義していますが、 その中で、UTF-8 は、たぶん、もっとも有名です。 UTF-8 は、可変長のエンコーディングで、Unicode 文字を 1 から 6 バイト。 他のエンコーディングは、UTF-16 と UTF-32 と、それらの大小のエンディアンの 変形(UTF-8 は、バイトオーダーと独立です)を含みます。 ISO/IEC 10646 は、UCS-2 と UCS-4 の encoding forms を定義しています。

エンコーディングについて -- たとえば、surrogatesbyte order marks(BOMs) -- もっと知りたければ perlunicode を 見て下さい。

Perl の Unicode サポート

Perl 5.6.0 から、Perl は、Unicode をネイティブに扱う能力を持っていました。 しかし、Perl 5.8.0 の最初の RC リリースは、重大な Unicode の仕事です。 メンテナンスリリースの 5.6.1 は、最初の Unicode 実装の多くの問題を 修正しました。 ですが、たとえば、5.6.1 で、Unicode での正規表現はまだ働きません。

Perl 5.8.0 から、use utf8 の使用は、遥かに限られた状況でのみ 必要になりました。 初期のリリースでは、utf8 プラグマは、現在のブロックやファイルの操作が、 Unicode であると明示するのを宣言するために使われました。 このモデルは間違いが見つけられるか、少なくとも、不格好です: 操作に添付するかわりに、"Unicodeness" は、今や、データに持ち込まれています。 唯一残されている、明示的に use utf8 をする必要がある場所は: Perl スクリプト自身が UTF-8 でエンコードされていれば、 識別子の名前、文字の中と、正規表現のリテラルに、UTF-8 を使うことができます。 これは、デフォルトではありません。 なぜなら、レガシーの 8-bit データのスクリプトが壊れるからです。 utf8 を参照してください。

Perl の Unicode モデル

Perl は、Perl 5.6 より前での 8 ビットネイティブのバイト列の文字列と、 Unicode 文字の文字列の両方をサポートします。 方針は、Perl は、可能な限り長く 8 ビットバイト列としてデータを 保とうとします。 ですが、Unicode 性が避けられなくなった時点で、 データは(ほぼ)透過的に Unicode に昇格されます。 ここには問題があります -- "The "Unicode Bug"" in perlunicode を 参照してください。

内部的には、Perl は、プラットフォームの 8 ビット文字セット (例えば、Latin-1)は、デフォルトは UTF-8 ですが、Unicode 文字列に エンコードします。 特に、文字列中の、全ての符号位置は、0xFF 以下であれば、 Perl は、ネイティブの 8 ビットの文字セットを使います。 そうでなければ、UTF-8 を使います。

Perl のユーザは普通は、Perl がその内部文字列をたまたま、どのように エンコードするかを、知る必要も、気にする必要もありませんが、Unicode 文字列を PerlIO 層なしに (「デフォルトの」エンコーディングで) ストリームに 出力しようとすると、関係するようになります。 このようなケースでは、内部的に使われている生のバイト列(それぞれの 文字列の必要に応じて、ネイティブの文字セットか、UTF-8)が使われます。 それらの文字列に、0x00FF を超える文字があれば、"Wide character" の警告が 出されます。

たとえば、

      perl -e 'print "\x{DF}\n", "\x{0100}\x{DF}\n"'

ネイティブのバイト列と UTF-8 の、まったく役に立たない混合もまた、 同様に警告を出します:

     Wide character in print at ...

UTF-8 を出力するために、:encoding:utf8 出力層を使います。 先頭にこれを追加することで:

      binmode(STDOUT, ":utf8");

このサンプルプログラムが、出力が完全に UTF-8 であることを保証し、 プログラムの警告を削除します。

-C コマンドラインスイッチか、PERL_UNICODE 環境変数のどちらか一方を 使うことで、標準ファイルハンドルと、デフォルトの open() 層と、 @ARGV の UTF-8 化を自動的に有効に出来ます; perlrun-C スイッチのドキュメントを見て下さい。

このことは、Perl が他のソフトウェアの動きを予測することを意味するのに 気をつけて下さい: Perl が STDIN が UTF-8 であるべきと信じるように主導されていて、 他のコマンドからくる STDIN が UTF-8 でなければ、 Perl は、不正な UTF-8 であると文句を言います。

Unicode と、I/O の結合の特徴もまた、新しい PerlIO の特徴を使うことを 必要とします。 ほとんど全ての Perl5.8 プラットフォームは、PerlIO を使います。 ですが: "perl -V" を動かして、useperlio=define を見れば、PerlIO を 使っているかどうか、わかります。

Unicode と EBCDIC

Perl 5.8.0 は、EBCDIC プラットフォームでもまた、Unicode をサポートします。 ここでは、各ステップで追加の変換が必要になるので、Unicode サポートは 実装が若干より複雑になります。

後の Perl リリースには EBCDIC プラットフォームで動作しないコードが追加され、 誰も文句を言わなかったので、相違は続いています。 もし Perl を EBCDIC プラットフォームで実行したいなら、 perlbug@perl.org にメールを送ってください。

EBCDIC プラットフォームでは、内部 Unicode エンコーディング形式は UTF-8 ではなく UTF-EBCDIC です。 この違いは、ASCII 文字はそのまま UTF-8 にエンコードされるという点において "ASCII セーフ" ですが、一方 UTF-EBCDIC は "EBCDIC セーフ" です。

Unicode の作成

0xFF を超える符号位置のリテラルで Unicode 文字を作るためには、 \x{...} 記法をダブルクォートされた文字列の中で使います。

    my $smiley = "\x{263a}";

同様に、正規表現の中でも使えます。

    $smiley =~ /\x{263a}/;

chr() を使って、実行時に:

    my $hebrew_alef = chr(0x05d0);

全てのこれらの数字のコードを見つける方法は、"Further Resources" を 参照してください。

当然、ord() は、逆を行います: 文字を符号位置に変えます。

0x100(10 進の 256)未満の引数の、\x.. ({} なしで、 2 つの 16 進数の数字のみです)と、\x{...} と、chr(...) は、古い Perl との互換性のために、8 ビットの文字列を生成します。 x100 かそれ以上の引数では、常に Unicode 文字が生成されます。 何が何でも、数字の値の Unicode 文字を、強制的に生成したければ、 \x..\x{...}chr() の代わりに、pack("U", ...) を使って下さい。

ダブルクォートされた文字列内で、名前で文字を呼び出すために、 charnames プラグマを使うこともできます:

    use charnames ':full';
    my $arabic_alef = "\N{ARABIC LETTER ALEF}";

そして、上述のように、数字を Unicode 文字に、pack() できます:

   my $georgian_an  = pack("U", 0x10a0);

\x{...} と、\N{...} の両方は、コンパイル時の文字列定数です: その中に変数を使うことはできません。 類似のことを実行時にしたいなら、c<chr()> と、charnames::vianame() を 使ってください。

結果を Unicode 文字に強制したいなら、特別な、"U0" 接頭辞を使って下さい。 これは引数を消費しませんが、引き続くバイト列を Unicode 文字の UTF-8 エンコーディングとして解釈させます:

   my $chars = pack("U0W*", 0x80, 0x42);

同様に、特殊な "C0" 接頭辞を使うことによって、このような UTF-8 の解釈を 停止させることができます。

Unicode を扱う

Unicode を扱うことは、多くの部分にとって、透過的です: 文字列をいつものように使うだけです。 index()length()substr() のような関数は Unicode 文字列で 動きます; 正規表現も Unicode 文字列で動きます(perlunicodeperlretut を 参照してください)。

Perl は書記素クラスタを別々の文字と考えていることに注意して下さい。 ですので、例えば

    use charnames ':full';
    print length("\N{LATIN CAPITAL LETTER A}\N{COMBINING ACUTE ACCENT}"), "\n";

これは 1 ではなく、2 を表示します。 唯一の例外は、正規表現に拡張書記素クラスタにマッチするために、\X が ある場合です。

しかし、レガシーエンコーディング、I/O、そしてある種の特殊な状況では、 人生はそれほど透過的ではありません:

レガシーエンコーディング

レガシーデータと Unicode とを組み合わせる時は、 レガシーデータを Unicode に昇格しなければなりません。 通常、ISO 8859-1 (か、必要なら EBCDIC)が仮定されます。

Encode モジュールは多くのエンコーディングを知っており、 それらのエンコーディングの間の変換をするインターフェースを持っています。

    use Encode 'decode';
    $data = decode("iso-8859-3", $data); # convert from legacy to utf-8

Unicode I/O

通常、Unicode データを書き出すことは、

    print FH $some_string_with_unicode, "\n";

Unicode 文字列を内部的にエンコードするのにたまたまつかわれている、 生のバイト列を生成することです。 Perl の内部エンコーディングは、そのときに、文字列にたまたまある文字と 同じように、システム依存です。 どの文字も、符号位置が 0x100 以上なら、警告がでます。 出力が明示的に、望んでいるエンコーディングにレンダリングされていることを 保証し、警告を避けるために、望んでいるエンコーディングでストリームを open してください。 いくつか例示します:

    open FH, ">:utf8", "file";

    open FH, ">:encoding(ucs2)",      "file";
    open FH, ">:encoding(UTF-8)",     "file";
    open FH, ">:encoding(shift_jis)", "file";

すでに開かれているストリームに関しては、binmode() を使います:

    binmode(STDOUT, ":utf8");

    binmode(STDOUT, ":encoding(ucs2)");
    binmode(STDOUT, ":encoding(UTF-8)");
    binmode(STDOUT, ":encoding(shift_jis)");

エンコーディング名のマッチングはルーズです: 大文字小文字は重要ではなく、 多くのエンコーディングでは、いくつかの別名があります。 :utf8 層は、常に、きっちりとそのように指定される必要があります。 このことは、エンコーディング名のルーズなマッチングの対象では ありません。 データが妥当な UTF8 であるかどうかを検証せずに受け入れるので、入力に 対しては :utf8 は安全ではないことにも注意してください。

:utf8 層に関しては、PerlIO を参照してください; :encoding() に関しては、Encode::PerlIO を参照してください; Encode モジュールでサポートされている、多くのエンコーディングに関しては、 Encode::Supported を参照してください。

Unicode かレガシーのエンコーディングどちらかでたまたまエンコードされている ファイルを読み込んでも、Perl の目で、魔法のように、データが Unicode に 変わったりしません。 そうするためには、ファイルを開くときに、適切な層を指定します。

    open(my $fh,'<:encoding(utf8)', 'anything');
    my $line_of_unicode = <$fh>;

    open(my $fh,'<:encoding(Big5)', 'anything');
    my $line_of_unicode = <$fh>;

I/O 層は、もっと柔軟に、open プラグマでもまた、指定することが出来ます。 open を参照するか、次の例を見て下さい。

    use open ':encoding(utf8)'; # input/output default encoding will be UTF-8
    open X, ">file";
    print X chr(0x100), "\n";
    close X;
    open Y, "<file";
    printf "%#x\n", ord(<Y>); # this should print 0x100
    close Y;

open プラグマで、:local 層も使えます:

    BEGIN { $ENV{LC_ALL} = $ENV{LANG} = 'ru_RU.KOI8-R' }
    # the :locale will probe the locale environment variables like LC_ALL
    use open OUT => ':locale'; # russki parusski
    open(O, ">koi8");
    print O chr(0x430); # Unicode CYRILLIC SMALL LETTER A = KOI8-R 0xc1
    close O;
    open(I, "<koi8");
    printf "%#x\n", ord(<I>), "\n"; # this should print 0xc1
    close I;

ストリームからファイルが読まれるときに、特定のエンコーディングから、 データを変換する I/O ストリーム上の透過的な層です。 その結果は常に Unicode です。

open プラグマは、デフォルトの層を設定することで、プラグマの後の 全ての open() 呼び出しに影響します。 あるストリームだけに影響を限定したいなら、open() 呼び出しで明示的な 層を使って下さい。

binmode() を使って、すでに開かれているストリームのエンコーディングを 変えることが出来ます; "binmode" in perlfunc を参照してください。

:locale は、現在(Perl 5.8.0 の時点で)、open()binmode() では 動きません。 open プラグマでのみ動きます。 :utf8:encoding(...) メソッドは、全ての open()binmode()open プラグマで動きます。

似たようなものに、ストリームに書き出すときに、自動的に Unicode を 特定のエンコーディングに変換する、出力ストリームの I/O 層を使うかも 知れません。 例えば、次のようなコードの断片は、(ISO-2022-JP, またの名を JIS として エンコードされている)" text.jis" ファイルの内容を、UTF-8 として エンコードされる "text.utf8" ファイルにコピーします。

    open(my $nihongo, '<:encoding(iso-2022-jp)', 'text.jis');
    open(my $unicode, '>:utf8',                  'text.utf8');
    while (<$nihongo>) { print $unicode $_ }

open() と、open プラグマの両方で使われているエンコーディングの 名前は、フレキシブルな名前でも使えます: koi8-rと、KOI8R は、 両方とも理解されます。

ISO、MIME、IANA、様々な他の標準化機関が認識している、一般的な エンコーディングが認識されます; より詳細なリストは、 Encode::Supported を参照してください。

read() は、文字を読み、文字の数を返します。 seek()tell() は、バイトカウントに関して操作します。 sysreadsysseek() も同様です。

デフォルト層がなければ、入力になんの変換もしないのがデフォルトの 振る舞いなので、繰り返しデータをエンコーディングすることで、 ファイルを展開し続けるコードを誤って書きやすいです。

    # BAD CODE WARNING
    open F, "file";
    local $/; ## read in the whole file of 8-bit characters
    $t = <F>;
    close F;
    open F, ">:encoding(utf8)", "file";
    print F $t; ## convert to UTF-8 on output
    close F;

このコードを 2 回実行すると、file の内容は、UTF-8 に、2 回 エンコードされます。 use open 'encoding(utf8)' は、バグを避けるでしょう; もしくは、UTF-8 として入力するために、File を、明示的に開くことです。

注意: :utf8:encoding の機能は、Perl が新しい PerlIO の機能で ビルドされている場合(ほとんどのシステムで、それがデフォルトです)にのみ 動作します。

Unicode をテキストとして表示する

Unicode を含んでいる Perl のスカラを、単純な ASCII(か、EBCDIC)の テキストとして、表示したいかもしれません。 下のサブルーチンは、引数を変換して、255 より大きい符号位置の Unicode 文字を、\x{...} として表示し、(\n のような)制御文字は、 \x.. として表示します。 残りの文字は、そのまま表示します:

   sub nice_string {
       join("",
         map { $_ > 255 ?                  # if wide character...
               sprintf("\\x{%04X}", $_) :  # \x{...}
               chr($_) =~ /[[:cntrl:]]/ ?  # else if control character ...
               sprintf("\\x%02X", $_) :    # \x..
               quotemeta(chr($_))          # else quoted or as themselves
         } unpack("W*", $_[0]));           # unpack Unicode characters
   }

たとえば、

   nice_string("foo\x{100}bar\n")

は、次のような文字列になり:

   'foo\x{0100}bar\x0A'

表示可能になります。

特殊な状況

発展した話題

その他

質問と回答

16 進記法

Unicode 標準は、16 進記法を使うのを好みます。 それは、256 の文字のブロックに Unicode を分割しているのが、 他の表記よりわかりやすいからです。 10 進記法を使うことも出来ますが、16 進記法を使うことを学べば、 Unicode 標準との暮らしが楽になります。 例えば、U+HHHH 表記は、16 進記法を使います。

0x の接頭辞は、16 進の数字を意味しています。 数字は、0-9 および a-f(か、A-F、大文字小文字は問いません)です。 それぞれの 16 進の数字は 4 ビット、1/2 バイトを表します。 print 0x..., "\n" は 16 進数を 10 進で見せます。 printf "%x\n", $decimal は 10 進数を 16 進で見せます。 "hex digits" の 16 進の数字があるなら、hex() 関数を使うことが出来ます。

    print 0x0009, "\n";    # 9
    print 0x000a, "\n";    # 10
    print 0x000f, "\n";    # 15
    print 0x0010, "\n";    # 16
    print 0x0011, "\n";    # 17
    print 0x0100, "\n";    # 256

    print 0x0041, "\n";    # 65

    printf "%x\n",  65;    # 41
    printf "%#x\n", 65;    # 0x41

    print hex("41"), "\n"; # 65

更なるリソース

古い Perl での Unicode

Perl 5.8.0 以降にアップグレード出来なくても、まだ、CPAN から利用できる、 Unicode::StringUnicode::Mmap8bUnicode::Map を使って、 いくつかの Unicode 処理ができます。 GNU recode がインストールされているなら、それの Perl フロントエンドである Convert::Recode を文字変換のために使えます。

下記のものは、ISO 8859-1 (Latin-1) バイト列から UTF-8 バイト列に (あるいはその逆に)素早く変換するものです。 このコードは古い Perl 5 でも動きます。

    # ISO 8859-1 to UTF-8
    s/([\x80-\xFF])/chr(0xC0|ord($1)>>6).chr(0x80|ord($1)&0x3F)/eg;

    # UTF-8 to ISO 8859-1
    s/([\xC2\xC3])([\x80-\xBF])/chr(ord($1)<<6&0xC0|ord($2)&0x3F)/eg;

SEE ALSO

perlunitut, perlunicode, Encode, open, utf8, bytes, perlretut, perlrun, Unicode::Collate, Unicode::Normalize, Unicode::UCD

謝辞

Thanks to the kind readers of the perl5-porters@perl.org, perl-unicode@perl.org, linux-utf8@nl.linux.org, and unicore@unicode.org mailing lists for their valuable feedback.

著者、著作権、ライセンス

Copyright 2001-2002 Jarkko Hietaniemi <jhi@iki.fi>

This document may be distributed under the same terms as Perl itself.