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 が最初に着想されたとき、世界中の文字は 16 ビットで表現できると 考えられていました; 0x0000
から 0xFFFF
までの最大 0x10000
(あるいは 65,536) 文字が必要であるということです。 これは間違っているとすぐに証明され、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 は一般的にはその文字のための 連続した未割り当ての符号位置の ブロック
を選びます。 今のところ、それらのブロックの符号位置の数は常に 16 で割り切れます。 現在のところ必要ではないブロック中の余地は将来の成長のために 未見割り当てのまま残されます。 しかし、後のリリースで利用可能な余地よりも多い符号位置が必要になり、 超えた文を扱うために、元のブロックと連続していない新しいブロックを どこかに割り当てる必要があることがあります。 従って、「ブロック」が適切な組織化方法ではないことが早く明らかになったので、 用字
(Script) 特性が作られました。 (後に改良された用字特性である Script_Extensions
も追加されました。) 溢れたブロックにある符号位置も元のものと同じ用字を持ちます。 用字の考え方は自然言語によりよく一致します: Latin
用字があり、Greek
用字があり、などです; 数学記号のような複数の用字で使われる文字のための Common
といった、 人工的な用字もいくつかあります。 用字は普通複数のブロックにわたっています。 用字に関するさらなる情報については、"Scripts" in perlunicode を 参照してください。 ブロックに分割されたものはありますが、それは、ほとんど完全に、 予想外のものです--文字がどのように割り当てられるかは不自然な結果です。 (この段落は導入の目的のために単純化しすぎていることに注意してください。 Unicode は実際には言語をエンコードするのではなく、それらの書記体系--用字--を エンコードします; そしてある用字は多くの言語で使われます。 Unicode は BAGGAGE CLAIM
のようなシンボルのような、実際には 言語ではないようなものもエンコードします。)
Unicode の符号位置は、抽象的な数字です。 この抽象的な数字を入出力するために、数字は、何らかの形で エンコード (encode) や シリアライズ (serialise) されなければなりません。 Unicode は、複数の character encoding forms を定義していますが、 その中で、UTF-8 は、もっとも一般的です。 UTF-8 は、可変長のエンコーディングで、Unicode 文字を 1 から 4 バイト。 他のエンコーディングは、UTF-16 と UTF-32 と、それらの大小のエンディアンの 変形(UTF-8 は、バイトオーダーと独立です)を含みます。 ISO/IEC 10646 は、UCS-2 と UCS-4 の encoding forms を定義しています。
エンコーディングについて -- 例えば、surrogates と byte order marks(BOMs) -- もっと知りたければ perlunicode を 見て下さい。
Perl v5.6.0 から、Perl は、Unicode をネイティブに扱う能力を持っていました。 しかし、重要な Unicode の作業をするためには、Perl v5.8.0 が最初の 推奨できるリリースです。 メンテナンスリリースである 5.6.1 は初期の Unicode 実装の多くの問題を 修正しましたが、例えば、5.6.1 で、Unicode での正規表現はまだ動作しません。 Perl v5.14.0 は、Unicode 対応がいくつかのコツを使うことなく(ほぼ)切れ目なく 統合された最初のリリースです。 (いくつかの例外があります。 1 番目として、quotemeta のいくつかの違いは Perl 5.16.0 から修正されました。 2 番目として、the range operator のいくつかの違いは Perl 5.26.0 から修正されました。 3 番目として、split のいくつかの違いは Perl 5.28.0 から修正されました。 )
この切れ目のない対応を有効にするには、use feature 'unicode_strings'
と します(これは use 5.012
またはそれ以上とすると自動的に選択されます)。 feature を参照してください。 (5.14 はまた、多くのバグおよび Unicode 標準からの逸脱を修正しています。)
Perl v5.8.0 以前では、use utf8
の使用は、現在のブロックやファイルの 操作が、Unicode であると明示するのを宣言するために使われました。 このモデルは間違っているか、少なくとも不格好であることがわかりました: 操作に添付するかわりに、"Unicodeness" は、今や、データに持ち込まれています。 Perl v5.8.0 から、唯一残されている、明示的に use utf8
をする必要がある 状況があります: Perl スクリプト自身が UTF-8 でエンコードされていれば、識別子の 名前および、文字の中と正規表現のリテラルに UTF-8 を使うことができます。 これはデフォルトではありません; なぜなら、レガシーな 8-bit データの スクリプトが壊れるからです。 utf8 を参照してください。
Perl は、Perl 5.6 より前での 8 ビットネイティブのバイト列の文字列と、 Unicode 文字の文字列の両方をサポートします。 一般的な方針は、Perl は、可能な限り長く 8 ビットバイト列としてデータを 保とうとします; しかし、Unicode 性が避けられなくなった時点で、 データは透過的に Unicode に昇格されます。 Perl v5.14.0 より前では、昇格は完全に透過的ではありませんでした ("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 対応が追加されました。 この対応は後のリリースで失効していましたが、5.22 に復活しました。 追加の変換が必要になるので、Unicode 対応は実装が若干より複雑になります。 さらなる情報については perlebcdic を参照してください。
EBCDIC プラットフォームでは、内部 Unicode エンコーディング形式は UTF-8 ではなく UTF-EBCDIC です。 この違いは、ASCII 文字はそのまま UTF-8 にエンコードされるという点において "ASCII セーフ" ですが、一方 UTF-EBCDIC は "EBCDIC セーフ" です; 全ての基本文字 (ASCII の等価物 (like "A"
, "0"
, "%"
, など) を 持つ全てのもの) は EBCDIC および UTF-EBCDIC で同じです。 しばしば、文書では "UTF-8" という用語を UTF-EBCDIC を含む意味で用います。 この文書でもそうです。
この章は、v5.22 以降の Perl から完全に適用されます。 それ以前のバージョンでの様々な問題は後述する "Earlier releases caveats" 節にあります。
リテラルで Unicode 文字を作るためには、 \N{...}
記法をダブルクォートされた文字列の中で使います。
my $smiley_from_name = "\N{WHITE SMILING FACE}";
my $smiley_from_code_point = "\N{U+263a}";
同様に、正規表現の中でも使えます。
$smiley =~ /\N{WHITE SMILING FACE}/;
$smiley =~ /\N{U+263a}/;
または、v5.32 から:
$smiley =~ /\p{Name=WHITE SMILING FACE}/;
$smiley =~ /\p{Name=whitesmilingface}/;
実行時に:
use charnames ();
my $hebrew_alef_from_name
= charnames::string_vianame("HEBREW LETTER ALEF");
my $hebrew_alef_from_code_point = charnames::string_vianame("U+05D0");
当然、ord()
は、逆を行います: 文字を符号位置に変えます。
その他の実行時の選択肢もあります。 pack()
を使えます:
my $hebrew_alef_from_code_point = pack("U", 0x05d0);
あるいは chr()
も使えますが、一般的な場合では余り便利ではありません:
$hebrew_alef_from_code_point = chr(utf8::unicode_to_native(0x05d0));
utf8::upgrade($hebrew_alef_from_code_point);
引数が 0xFF より大きい場合は utf8::unicode_to_native()
と utf8::upgrade()
は不要なので、 前述のものは次のようにも書けます
$hebrew_alef_from_code_point = chr(0x05d0);
0x5d0 は 255 より大きいからです。
\x{}
と \o{}
はダブルクォート風文字列の中でコンパイル時に 符号位置を指定するのにも使えますが、古い Perl との後方互換性のために、 256 より小さい符号位置に対する chr()
と同じ規則が適用されます。
utf8::unicode_to_native()
は Perl コードを EBCDIC プラットフォームと 互換性を持たせるために使われます。 もし、あなたのコードを非 ASCII プラットフォームで使おうとする人が いないことが 本当に 確実なら、これを省略できます。 Perl v5.22 から、ASCII プラットフォームでのこれの呼び出しは最適化により 削除されるので、これを追加することによる性能上のペナルティは全くありません。 あるいは単にこれを必要としない他の構文を使うことも出来ます。
これら全ての名前と数字のコードを見つける方法は、"Further Resources" を 参照してください。
EBCDIC プラットフォームでは、v5.22 より前では、\N{U+...}
の使用は 正しく動作しません。
v5.16 より前では、(U+...
符号位置ではなく) 文字名での \N{...}
の使用には use charnames :full
が必要です。
v5.14 より前では、(U+...
符号位置ではなく) 文字名での \N{...}
の使用には バグがあります。
charnames::string_vianame()
は v5.14 で導入されました。 これより前では、charnames::vianame()
は動作するはずですが、 引数が "U+..."
型式の場合のみです。 実行時 Unicode を文字名で扱うための最良の方法はおそらく次のようなものです:
use charnames ();
my $hebrew_alef_from_name
= pack("U", charnames::vianame("HEBREW LETTER ALEF"));
Unicode を扱うことは、ほとんどの部分では透過的です: 文字列をいつものように 使うだけです。 index()
、length()
、substr()
のような関数は Unicode 文字列で 動きます; 正規表現も Unicode 文字列で動きます(perlunicode と perlretut を参照してください)。
Perl は書記素クラスタを別々の文字と考えていることに注意して下さい; 従って、例えば
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
通常、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(UTF-8)', 'anything');
my $line_of_unicode = <$fh>;
open(my $fh,'<:encoding(Big5)', 'anything');
my $line_of_unicode = <$fh>;
I/O 層は、もっと柔軟に、open
プラグマでもまた、指定することが出来ます。 open を参照するか、次の例を見て下さい。
use open ':encoding(UTF-8)'; # 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
は、現在のところ 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()
は、sysseek()
と同様に バイトカウントに関して操作します。
sysread()
と syswrite()
は文字エンコーディング層を持つ ファイルハンドルに対して使うべきではありません; これは間違った振る舞いをして、 この振る舞いは perl 5.24 から廃止予定です。
デフォルト層がなければ、入力になんの変換もしないのがデフォルトの 振る舞いなので、繰り返しデータをエンコーディングすることで、 ファイルを展開し続けるコードを誤って書きやすいです。
# BAD CODE WARNING
open F, "file";
local $/; ## read in the whole file of 8-bit characters
$t = <F>;
close F;
open F, ">:encoding(UTF-8)", "file";
print F $t; ## convert to UTF-8 on output
close F;
このコードを 2 回実行すると、file の内容は、2 回 UTF-8 に エンコードされます。 use open ':encoding(UTF-8)'
でバグを避けられ、 もしくは、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'
表示可能になります。
(ここでは \\N{}
ではなく \\x{}
が使われています; なぜなら おそらくネイティブな値を見たいだろうからです。)
Perl 5.28 から、~
のようなビット演算子を、255 を超える符号位置を持つ 文字列に適用するのは不正になります。
vec() 関数は、255 を超える序数の値の文字を含んでいる文字列で、 使われると、驚くべき結果になるでしょう。 そのような場合では、その結果は文字の内部的なエンコーディングで一貫性が あります; しかし、他の多くでは違います。 ですので、そのようなことはしないでください; そして Perl 5.28 から、そのようなことをすると廃止予定メッセージが 出力され、Perl 5.32 で不正になります。
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 で修正され、5.18 で基本的に全体的に 修正されました。
文字列の照合(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 https://www.unicode.org/unicode/reports/tr10/ を参照してください。
文字の範囲とクラス
正規表現の大かっこ文字クラス(/[a-z]/
)内と、tr///
(y///
としても 知られる)演算子内では、自動的には Unicode 対応にはなりません。 これが意味することは、[A-Za-z]
は、自動的に "全てのアルファベット文字"を 意味するようにはなりません(8 ビットの文字であることすらも意味しません; そのためには、ロケール (perllocale) を使っているなら、/[[:alpha:]]/
を 使ってください; そうでなければ、8 ビットを認識する特性 \p{alpha}
を 使ってください)。
\p
(およびその反転である \P
) で始まる全ての特性は実際には Unicode に対応した文字クラスです。 これにはたくさんの種類があります; perluniprops を参照してください。
v5.22 から、正規表現パターン文字範囲の端の位置として、Unicode の符号位置を 使うことができ、幅はこれらの両端の位置の間の Unicode 符号位置全てを含みます。
qr/ [ \N{U+03} - \N{U+20} ] /xx
これは符号位置 \N{U+03}
, \N{U+04}
, ..., \N{U+20}
を含みます。
これは Perl v5.24 からこの振る舞いを tr///
の範囲でも動作します。
文字列から数字への変換
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
は、バイトエンコードされたままです。
文字列の長さではなく、文字列のバイト長を知る必要があるかもしれません。 そのためには、bytes
プラグマと length()
関数を使うだけです:
my $unicode = chr(0x100);
print length($unicode), "\n"; # will print 1
use bytes;
print length($unicode), "\n"; # will print 2
# (the 0xC4 0x80 of the UTF-8)
no bytes;
ファイルが使っているエンコーディングを見つけるには?
Encode::Guess を試してみることができますが、いくつかの制限があります。
あるエンコーディングで、データが妥当でないことを検出するには?
Encode
パッケージを使って、それを変換してみてください。 例えば、
use Encode 'decode';
if (eval { decode('UTF-8', $string, Encode::FB_CROAK); 1 }) {
# $string is valid UTF-8
} else {
# $string is not valid UTF-8
}
または 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 に信じさせることもできます:
$Unicode = $bytes;
utf8::decode($Unicode);
または:
$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 は、どのように動きますか?
ロケールが UTF-8 ロケールなら、 Perl v5.26 から、Perl は全てのカテゴリでうまく動作します; その前では、Perl v5.20 から、ソートと cmp
演算子で、 LC_COLLATE
の以外の全てのカテゴリで動作するようになりました。 しかし、標準の Unicode::Collate
, Unicode::Collate::Locale
モジュールは照合問題に関するより強力な解法を 提供し、より古いリリースでも動作することに注意してください。
その他のロケールでは、Perl 5.16 から、以下のように指定して、
use locale ':not_characters';
Perl がそれらでうまく動作するようにすることができます。 問題点は、ロケール文字集合と Unicode との間の変換を自分でする必要が あるということです。 上述の "Unicode I/O" には
use open ':locale';
を使う方法が記されていますが、:not_characters
を指定しなかったときに 起こるコツを含む完全な詳細は "Unicode and UTF-8" in perllocale にあります。
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>. Now maintained by Perl 5 Porters.
This document may be distributed under the same terms as Perl itself.