perluniintro - Perl Unicode の手引き
このドキュメントは、Unicode の一般的な考えと、 Perl で Unicode をどのように使うかを書いています。 Unicode のより深い扱いへのリファレンスについては "Further Resources" を 参照してください。
Unicode は、世界の全ての書記体系と、それに加えて、他の多くのシンボルを 体系化することを計画している文字集合標準です。
Unicode と ISO/IEC 10646 は、ほとんど全ての現代の文字集合標準を統合し、 全ての商業的に重要な現代の言語を含む 80 以上の書記体系と数百の以上の言語に 対応する組織的標準です。 もっとも大きい中国語、日本語、韓国語、それぞれの辞書の全ての文字もまた、 符号化されています。 この標準は、最終的には、250 の書記体系と、1000 以上の言語のほとんどすべての 文字を網羅する予定です。 Unicode 1.0 は 1991 年 10 月にリリースされ、Unicode 6.0 は 2010 年 10 月に リリースされました。
Unicode の 文字 は、抽象的な存在です。 Unicode の文字は、どんな特定の整数幅にも、特に、C 言語の char
にも 束縛されません。 Unicode は、言語中立で、表示中立です: Unicode は、テキストの言語をエンコードしませんし、 一般的にはフォントや他のグラフィカルなレイアウトの詳細を定義しません。 Unicode は、文字と、それらの文字からなるテキストを操作します。
Unicode は、LATIN CAPITAL LETTER A
や GREEK SMALL LETTER ALPHA
のような 文字と、その文字について固有の番号を定義します; この場合はそれぞれ、 0x0041 と 0x03B1 になります。 このような固有の番号は、符号位置 (code point) と呼ばれます。 符号位置は基本的には全ての Unicode 文字の集合の中の文字の位置なので、 Perl では、序数 (ordinal) がしばしば同じ意味として使われます。
Unicode 標準は、符号位置に 16 進記法を使うのを好みます。 0x0041
のような番号に馴染みがなければ、後のセクション、 "Hexadecimal Notation" を覗いて見て下さい。 Unicode 標準は、U+0041 LATIN CAPITAL LETTER A
という表記を使って、 16 進法の符号位置と標準的な文字の名前を書きます。
Unicode はまた、「大文字」、「小文字」、「10 進数字」、「句読点: のような、 様々な文字の 特性 (property) を定義します; これらの特性は、文字の名前と 独立です。 更に、様々な文字に対する、大文字化や小文字化や並び替えといった操作が 定義されています。
Unicode 論理 「文字」は、実際には一つ以上の 実際 の「文字」または 符号位置から構成されます。 西洋の言語では、これは (LATIN CAPITAL LETTER A
のような)、基底文字 (base character) に続いて、一つ以上の(COMBINING ACUTE ACCENT
のような) 修飾字 (modifiers) によってモデル化されています。、 この基底文字と修飾字の並びは、結合文字の並び (combining character sequence) と呼ばれます。 一部の非西洋言語ではより複雑なモデルが必要なので、Unicode は 書記素クラスタ (grapheme cluster) という概念を作成し、後に 拡張書記素クラスタ (extended grapheme cluster) という形に洗練させました。 例えば、ハングル音節文字は一つの論理文字として考えられますが、とても しばしば三つの実際の Unocde 文字から構成されています: 先頭子音に引き続いて内部母音、それに引き続いて末尾子音です。
これらの拡張書記素クラスタを「複数の文字」と呼ぶかどうかは、どのような 視点を取るかによります。 プログラマならば、おそらく、この順番のそれぞれの要素を、 1 つの単位、あるいは「文字」として、見ようとするでしょう。 しかし、ユーザの視点では、おそらくユーザの言語の文脈でみえるような ものなので、並び全体を一つの「文字」として見るでしょう。 この文書では、プログラマの視点を取ります: 一つの「文字」は一つの Unicode 符号位置です。
一部の基底文字と修飾字の組み合わせは、合成済 (precomposed) 文字です。 例えば、LATIN CAPITAL LETTER A
に引き続いて COMBINING ACUTE ACCENT
の並びのように、等価な単一の文字があります。 これは LATIN CAPITAL LETTER A WITH ACUTE
と呼ばれます。 しかし、これらの合成済文字は一部の組み合わせでのみ利用可能で、主に Unicode と(ISO 8859 のような)伝統的な標準との間の往復変換に対応するために あります。 Unicode がするように並びを使うと、より多くの潜在的な書記素クラスタを 表現するためにより少ない基本構築ブロック(符号位置)で済むようになります。 等価な形式の変換に対応するために、様々な 正規化形式 (normalization form) も定義されています。 従って、LATIN CAPITAL LETTER A WITH ACUTE
は 正規化形式 C (Normalization Form Composed) (短縮形 NFC)にあり、 LATIN CAPITAL LETTER A
に引き続いて COMBINING ACUTE ACCENT
の並びは 正規化形式 D (Normalization Form Decomposed) (NFD) にある同じ文字を 表現します。
レガシーエンコーディングとの後方互換性のために、 "全ての文字に固有の番号" という考えは、少々壊れています: その代わりに、"少なくとも全ての文字に 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、または、基本多言語面 (Basic Multilingual Plane)(BMP) と呼ばれます。 Unicode 3.1 で、全部で 17(そう、17)の面が定義されました -- ですが、 まだ、定義された全文字のどこにも、まだ近くにありません。
もう一つ神話は、Unicode ブロックに関するものです -- これが何か言語を 取り扱うことがある -- それぞれのブロックはある言語か言語の集合で使われている文字を 定義するということです。 これもまた真実ではありません。 ブロックに分割されたものはありますが、それは、ほとんど完全に、 予想外のものです--文字がどのように割り当てられるかは不自然な結果です。 代わりに、用字 (scripts) と呼ばれる、より有益なコンセプトがあります: Latin
用字、Greek
用字などがあります。 用字は、ふつう、いくつかのブロックの変えられた部分を測っています。 詳しくは、"Scripts" in perlunicode を見て下さい。
Unicode の符号位置は、抽象的な数字です。 この抽象的な数字を入出力するために、数字は、何らかの形で エンコード (encode) や シリアライズ (serialise) されなければなりません。 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 を定義しています。
エンコーディングについて -- 例えば、surrogates と byte order marks(BOMs) -- もっと知りたければ perlunicode を 見て下さい。
Perl 5.6.0 から、Perl は、Unicode をネイティブに扱う能力を持っていました。 しかし、重要な Unicode の作業をするためには、Perl 5.8.0 が最初の 推奨できるリリースです。 メンテナンスリリースである 5.6.1 は初期の Unicode 実装の多くの問題を 修正しましたが、例えば、5.6.1 で、Unicode での正規表現はまだ動作しません。 Perl 5.14.0 は、Unicode 対応がいくつかのコツを使うことなく(ほぼ)切れ目なく 統合された最初のリリースです (一部の違いのある例外は quotemeta にあります)。 この切れ目のない対応を有効にするには、use feature 'unicode_strings'
と します(これは use 5.012
またはそれ以上とすると自動的に選択されます)。 feature を参照してください。 (5.14 はまた、多くのバグおよび Unicode 標準からの逸脱を修正しています。)
Perl 5.8.0 以前では、use utf8
の使用は、現在のブロックやファイルの 操作が、Unicode であると明示するのを宣言するために使われました。 このモデルは間違っているか、少なくとも不格好であることがわかりました: 操作に添付するかわりに、"Unicodeness" は、今や、データに持ち込まれています。 Perl 5.8.0 から、唯一残されている、明示的に use utf8
をする必要がある 状況があります: Perl スクリプト自身が UTF-8 でエンコードされていれば、識別子の 名前および、文字の中と正規表現のリテラルに UTF-8 を使うことができます。 これはデフォルトではありません; なぜなら、レガシーな 8-bit データの スクリプトが壊れるからです。 utf8 を参照してください。
Perl は、Perl 5.6 より前での 8 ビットネイティブのバイト列の文字列と、 Unicode 文字の文字列の両方をサポートします。 一般的な方針は、Perl は、可能な限り長く 8 ビットバイト列としてデータを 保とうとします; しかし、Unicode 性が避けられなくなった時点で、 データは透過的に Unicode に昇格されます。 Perl 5.14 より前では、昇格は完全に透過的ではありませんでした ("The "Unicode Bug"" in perlunicode を参照してください)し、後方互換性のために、 完全な透過性は use feature 'unicode_strings'
とするか(feature 参照) use 5.012
(またはそれ以上) が選択されなければ得られませんでした。
内部的には、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 を 使っているかどうか、わかります。
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 セーフ" です。
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::string_vianame()
を 使ってください。
結果を Unicode 文字に強制したいなら、特別な、"U0"
接頭辞を使って下さい。 これは引数を消費しませんが、引き続くバイト列を Unicode 文字の UTF-8 エンコーディングとして解釈させます:
my $chars = pack("U0W*", 0x80, 0x42);
同様に、特殊な "C0"
接頭辞を使うことによって、このような UTF-8 の解釈を 停止させることができます。
Unicode を扱うことは、ほとんどの部分では透過的です: 文字列をいつものように 使うだけです。 index()
、length()
、substr()
のような関数は Unicode 文字列で 動きます; 正規表現も Unicode 文字列で動きます(perlunicode と perlretut を参照してください)。
Perl は書記素クラスタを別々の文字と考えていることに注意して下さい; 従って、例えば
use charnames ':full';
print length("\N{LATIN CAPITAL LETTER A}\N{COMBINING ACUTE ACCENT}"), "\n";
これは 1 ではなく、2 を表示します。 唯一の例外は、正規表現に拡張書記素クラスタにマッチするために、\X
が ある場合です。 (従って正規表現内の \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 データを書き出すことは、
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
層は、常に、きっちりとそのように指定される必要があります; このことは、エンコーディング名のルーズなマッチングの対象では ありません。 また、今のところデータが妥当な UTF-8 であるかどうかを検証せずに受け入れるので、 入力に対しては :utf8
は安全ではないことにも注意してください; 代わりに :encoding(utf-8)
(ハイフンありかなしかどちらか) を使うべきです。
: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()
は、sysread
と sysseek()
と同様に バイトカウントに関して操作します。
デフォルト層がなければ、入力になんの変換もしないのがデフォルトの 振る舞いなので、繰り返しデータをエンコーディングすることで、 ファイルを展開し続けるコードを誤って書きやすいです。
# 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 の内容は、2 回 UTF-8 に エンコードされます。 use open 'encoding(utf8)'
でバグを避けられ、 もしくは、UTF-8 として入力するために、File を、明示的に開くことです。
注意: :utf8
と :encoding
の機能は、Perl が新しい PerlIO の機能で ビルドされている場合(ほとんどのシステムで、それがデフォルトです)にのみ 動作します。
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'
表示可能になります。
演算子 ~ と、vec() についてのちょっとした補足
演算子 ~
は、255 を超える序数の値の文字を含んでいる文字列で、 使われると、驚くべき結果になるでしょう。 そのような場合では、その結果は文字の内部的なエンコーディングで一貫性が あります; しかし、他の多くでは違います。 ですので、そのようなことはしないでください。 vec()
も同様です: 符号位置の値ではなく、内部的にエンコードされた、 Unicode 文字列のビットパターンを操作することになります; おそらく、それは望んだことではないでしょう。
Perl の内部エンコーディングをのぞき見る
Perl がどのように、特定の Unicode 文字列をエンコードしているかを、 Perl の普通のユーザは気にするべきではありません (Unicode で文字列の内容に達する普通の方法 -- 入出力によって -- は、常に 明示的に定義された I/O 層を経由すべきだからです)。 ですが、もし必要なら、隠れている裏側を見る 2 つの方法があります。
Unicode 文字の内部エンコーディングの内側を覗き見る方法の 1 つは、 エンコーディングが何であろうとも文字列のバイト列を得るために unpack("C*", ...
を使うか、UTF-8 エンコーディングのバイト列を得るために unpack("U0..", ...)
を使うことです:
# this prints c4 80 for the UTF-8 bytes 0xc4 0x80
print join(" ", unpack("U0(H2)*", pack("U", 0x100))), "\n";
もう一つの方法は、Dvel::Peek モジュールを使うことです:
perl -MDevel::Peek -e 'Dump(chr(0x100))'
これは、FLAGS の UTF8
フラグと、UTF-8 バイトと、PV
の中の Unicode 文字の両方を見せます。 このドキュメントの後にある、utf8::is_utf8()
機能についての議論も 参照してください。
文字列の等価性
文字列の等価性の疑問は、Unicode でいくぶん複雑になります: "等価" で、何を意味していますか?
(IS LATIN CAPITAL LETTER A WITH ACCUTE
と LATIN CAPITAL LETTER A
は、等しいでしょうか?)
短く答えれば次のようになります; デフォルトでは、Perl は(eq
と、ne
で)等価性を 比較しますが、これらは、文字の符号位置でのみに基づいています。 上のケースでは、答えはいいえです(0x00C1 != 0x0041 ですから)。 しかし、どんな CAPITAL LETTER A も等しいと考えるべき時や、大文字小文字に 関わらずどんな A も等しいと考えるべき時もあります。
長く答えるなら、文字の正規化と大文字小文字の問題を考える必要があります: Unicode::Normalize、Unicode テクニカルレポート #15 Unicode Normalization Forms と Unicode Standard の大文字小文字マッピングの 章を参照してください。
Perl 5.8.0 から、Case Mappings/SpecialCasing の、 「完全な」大文字小文字の畳み込みが実装されていますが、qr//i
にバグが 残っています; ほとんどは 5.14 で修正されました。
文字列の照合(Collation)
文字列がうまくソートされている(あるいは Unicode の業界用語を使えば、 照合されている(collated))のを好みます。 ですが、再び、照合で何を意味していますか?
(LATIN CAPITAL LETTER A WITH ACUTE
は、 LATIN CAPITAL LETTER A WITH GRAVE
より、 前でしょうか後でしょうか?)
短く答えれば次のようになります; Perl は、文字列を、(lt
、le
、cmp
、ge
、gt
)で比較しますが、 これらは、文字の符号位置でのみに基づいています。 上のケースでは、答えは、0x00C1
> 0x00C0
ですので、"後"になります。
長く答えるなら、「場合によります」; 良い答えは、(とても少なくとも)言語のコンテキストを知らずには、 与えられません。 Unicode::Collate, Unicode Collation Algorithm http://www.unicode.org/unicode/reports/tr10/ を参照してください。
文字の範囲とクラス
正規表現の大かっこ文字クラス(/[a-z]/
)内と、tr///
(y///
としても 知られる)演算子内では、自動的には Unicode 対応にはなりません。 これが意味することは、[A-Za-z]
は、自動的に "全てのアルファベット文字"を 意味するようにはなりません(8 ビットの文字であることすらも意味しません; そのためには、ロケール (perllocale) を使っているなら、/[[:alpha:]]/
を 使ってください; そうでなければ、8 ビットを認識する特性 \p{alpha}
を 使ってください)。
\p
(およびその反転である \P
) で始まる全ての特性は実際には Unicode に対応した文字クラスです。 これにはたくさんの種類があります; perluniprops を参照してください。
文字の範囲の端の位置として、Unicode の符号位置を使うことができ、幅はこれらの 両端の位置の間の Unicode 符号位置全てを含みます。
文字列から数字への変換
Unicode は、なじみのある、アラビアやインドの数字のような 0 から 9 に加えて、 複数の他の 10 進数--と数字の--文字を、定義します。 Perl は、ASCII の 0 から 9(と、16 進法の ASCII の a から f)以外の数字の、 文字列から数への変換をサポートしません。 任意の Unicode 文字列からの安全な変換を行うには、"num()" in Unicode::UCD を 使ってください。
古いスクリプトは壊れるでしょうか?
たぶん、壊れません。 どうにかして、Unicode 文字を生成していなければ、古い挙動は保護されます。 振る舞いが変更され、Unicode を生成し始める唯一のものは、古い chr()
は 引数として 255 を超える値が指定されると、255 を法とした文字が生成される というものです。 例えば、chr(300)
は、chr(45)
あるいは (ASCII の)"-" と同じでした; 現在ではそれは、LATIN CAPITAL LETTER I WITH BREVE です。
私のスクリプトを Unicode で動かすには?
Unicode データを生成するまで、ほとんど何もする必要はありません。 もっとも重要なものは、Unicode として、入力を得ることです; なので、以前の I/O の議論を見て下さい。 完全に切れ目のない Unicode 対応を使うには、スクリプトに use feature 'unicode_strings'
(または use 5.012
またはそれ以上) を 追加してください。
Unicode の文字列かどうかを知るには?
気にする必要はないはずです。 しかし、Perl が 5.14.0 より前か、use feature 'unicode_strings'
または use 5.012
(またはそれ以上) が指定されていない場合は必要が あるかもしれません; 範囲 128 から 256 の符号位置の意味論は、文字列が Unicode で保管されているかどうかによって異なるからです。 ("When Unicode Does Not Happen" in perlunicode を参照してください。)
文字列が Unicode かどうかを決定するには、以下を使います:
print utf8::is_utf8($string) ? 1 : 0, "\n";
しかし、これは、文字列の文字のすべてが UTF-8 でエンコードされているとか、 文字のすべてが 0xFF(255)(あるいは 0x80(128)) より大きい符号位置を 持つとか、文字列に文字が含まれているかとかいうことを 意味するわけではないことに注意してください。 is_utf8()
がすることの全ては、$string
につけられている内部の "utf8ness" フラグの値を返すことです。 フラグが無効であれば、スカラ内のバイト列は、シングルバイト エンコーディングとして解釈されます。 フラグが有効であれば、スカラ内のバイト列は、(可変長で、おそらくマルチバイトの) UTF-8 でエンコードされた文字の符号位置として解釈されます。 UTF-8 でエンコードされた文字列に追加されたバイトは自動的に UTF-8 に 昇格されます。 (ダブルクオートされた語句、明示的な連結、printf/sprintf パラメタ 置換によって)非 UTF-8 と、UTF-8 のスカラがマージされた場合、この結果は、 バイト文字列のコピーが UTF-8 で昇格されたかのように、 UTF-8 でエンコードされています: 例えば、
$a = "ab\x80c";
$b = "\x{100}";
print "$a = $b\n";
出力する文字列は UTF-8 エンコードされた ab\x80c = \x{100}\n
になりますが、 $a
は、バイトエンコードされたままです。
文字列の長さではなく、文字列のバイト長を知る必要があるかもしれません。 そのためには、Encode::encode_utf8()
関数か、bytes
プラグマと length()
関数を使うだけです:
my $unicode = chr(0x100);
print length($unicode), "\n"; # will print 1
require Encode;
print length(Encode::encode_utf8($unicode)), "\n"; # will print 2
use bytes;
print length($unicode), "\n"; # will also print 2
# (the 0xC4 0x80 of the UTF-8)
no bytes;
ファイルが使っているエンコーディングを見つけるには?
Encode::Guess を試してみることができますが、いくつかの制限があります。
あるエンコーディングで、データが妥当でないことを検出するには?
Encode
パッケージを使って、それを変換してみてください。 例えば、
use Encode 'decode_utf8';
if (eval { decode_utf8($string, Encode::FB_CROAK); 1 }) {
# $string is valid utf8
} else {
# $string is not valid utf8
}
または unpack
を使ってデコードしてみてください:
use warnings;
@chars = unpack("C0U*", $string_of_bytes_that_I_think_is_utf8);
妥当でなければ、Malformed UTF-8 character
の警告が出ます。 "C0" は、「文字列を文字単位で処理する」ことを意味します。 それ以外では、unpack("U*", ...)
は (フォーマット文字列が U
で 始まっている場合のデフォルトである)U0
モードで動作し、ターゲット文字列の UTF08 エンコーディングでのバイト数を返し、このようなことは常に動作します。
バイナリデータを特定のエンコーディングに変換したり、その逆をするには?
たぶん、思うようには有益ではないでしょう。 ふつう、必要とするべきではありません。
ある意味では、あなたが尋ねようとしていることはほとんど意味はありません: エンコーディングは文字のためのもので、バイナリデータは「文字」ではないので、 「データ」を何かのエンコーディングに変換するということは、 バイナリデータの文字セットとエンコーディングが分かっていない限り無意味です; そして分かっているならそれは単なるバイナリデータではないですよね?
どのエンコーディングで解釈するべきか分かっている生のバイト列がある場合、 Encode
が使えます:
use Encode 'from_to';
from_to($data, "iso-8859-1", "utf-8"); # from latin-1 to utf-8
from_to()
の呼び出しは $data
のバイト列を変更しますが、Perl が 関知する限りにおいては文字列の性質は何も変わりません。 呼び出しの前後の両方において、文字列 $data
は単に 8 ビットのバイトの 塊です。 Perl が関知するかぎりにおいては、文字列のエンコーディングは 「システムにネイティブな 8 ビットのバイト列」のままです。
これを架空の 'Translate' モジュールと関連付けることもできます:
use Translate;
my $phrase = "Yes";
Translate::from_to($phrase, 'english', 'deutsch');
## phrase now contains "Ja"
文字列の内容は変わりますが、文字列の性質は変わりません。 Perl は文字列の内容が肯定を意味するという呼び出し前の状態よりも多く、 呼び出しによって何かを知ることはありません。
データの変換に戻ります。 もしシステムのネイティブな 8 ビットエンコーディング(例えば、Latin-1, EBCDIC など)のデータを持っている(あるいは欲しい)場合は、Unicode との変換に pack/unpack を使えます。
$native_string = pack("W*", unpack("U*", $Unicode_string));
$Unicode_string = pack("U*", unpack("W*", $native_string));
あなたはバイト列が妥当な UTF-8 であると 分かっている けれども、Perl が 知らない場合、Perl に信じさせることもできます:
use Encode 'decode_utf8';
$Unicode = decode_utf8($bytes);
または:
$Unicode = pack("U0a*", $bytes);
UTF-8 シーケンスを作るバイト列は以下のようにして見つけられます
@bytes = unpack("C*", $Unicode_string)
整形された Unicode は以下のようにして作成できます
$Unicode_string = pack("U*", 0xff, ...)
Unicode を表示するには? Unicode を入力するには?
http://www.alanwood.net/unicode/ と http://www.cl.cam.ac.uk/~mgk25/unicode.html を参照してください。
伝統的なロケールと Unicode は、どのように動きますか?
Perl はこの二つを分けたままにしようとします。 255 より大きい符号位置は Unicode として扱われます; 256 より小さいものは、 一般的にはロケールです。 これは、Unicode で 255/256 の境界をまたいでマッチングするような大文字小文字を 無視した正規表現を例外として、かなりうまく動きます。 これらは許されません。 また、\p{}
と \N{}
の構文は、256 より小さい符号位置でも Unicode の 値であると暗黙に仮定します。 -C
スイッチと、それに対応する環境変数である $ENV{PERL_UNICODE}
の記述については、perlrun も参照してください; 様々な Unicode の機能が、どのように可能になっているのか、例えば、 ロケールの設定によって、が、わかります。
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
Unicode Consortium
Unicode FAQ
Unicode Glossary
Unicode 関連の推奨参照リスト
The Unicode Consortium には記事と本の一覧があり、Unicode のより深い 扱いについてより詳しく書かれています: http://unicode.org/resources/readinglist.html
Unicode Useful Resources
Unicode and Multilingual Support in HTML, Fonts, Web Browsers and Other Applications
UTF-8 and Unicode FAQ for Unix/Linux
Legacy Character Sets
Unicode::UCD
モジュールを使って、Unicode データファイルから 様々な情報を調べることができます。
Perl 5.8.0 以降にアップグレード出来なくても、まだ、CPAN から利用できる、 Unicode::String
、Unicode::Mmap8
、bUnicode::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;
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-2011 Jarkko Hietaniemi <jhi@iki.fi>
This document may be distributed under the same terms as Perl itself.