perllocale - Perl のロケール操作 (国際化と地域化)
まず最初に、ASCII、つまり "American Standard Code for Information Interchange" がありました; これは、英語アルファベットとドル建て 通貨を使うアメリカ人にとってはうまくいきました。 しかしこれは、ポンド貨(通貨の記号は ASCII にはありません)のような異なった 通貨を使っているかもしれないその他の英語話者に取ってすらあまりうまく いきませんでした; そして世界中の何百ものその他の言語にとっては絶望的に 無力でした。
これらの欠陥に対処するために、ロケールという概念が考案されました (正式には ISO C, XPG4, POSIX 1.c "locale system")。 そしてアプリケーションはロケール機構を使って書かれ、そして 書かれようとしていました。 アプリケーションにそういったユーザーの選択を考慮させるためのプロセスは、 国際化(internationalization)と呼ばれます(これはしばしば i18n と 省略されます); アプリケーションを特定の選択の集合に対応させることは 地域化(localization、l10n)として知られています。
Perl はロケールシステムに対応するように拡張されました。 これは一つのプラグマ、一つの関数呼び出し、いくつかの環境変数を使って、 アプリケーション毎に制御します。
残念ながら、ロケールにはかなりの数の設計上の(そしてしばしば実装上の)欠陥が あります。 Unicode (これに関する紹介については perlunitut を参照してください) は、この設計上の欠陥に部分的に対処するために 発明され、そして最近では、Unicode を基とした 一連の 「UTF-8 ロケール」があります。 これらは文字集合は Unicode で、UTF-8 でエンコードされています。 v5.20 から、Perl は UTF-8 ロケールに完全に対応しています; ただしソートと 文字列比較を除きます。 (これらのためには Unicode::Collate を使ってください。) Perl 古い非 UTF-8 ロケールも対応し続けています。
(Unicode はまた、POSIX ロケールシステムで利用可能なものよりも多くの種類の 情報を含む CLDR
, "Common Locale Data Repository", http://cldr.unicode.org/ を作成します。 これを書いている時点で、この XML エンコードされたデータへのアクセスを提供する モジュールはありません。 しかし、ロケールの多くは POSIX のデータを展開したもののみを持ち、 http://unicode.org/Public/cldr/latest/ の UTF-8 ロケールとして 利用可能です。)
ロケールとは、世界中の様々なコミュニティがその世界をどのように カテゴリ化しているかについての様々な側面を記述したデータの集合です。 これらのカテゴリは以下の型に分解されます(一部は概略の説明もあります):
LC_NUMERIC
: 数値フォーマットこれは人間に対する可読性のために数値をどのようにフォーマットするかを示します; たとえば小数点として使われる文字です。
LC_MONETARY
: 通貨量のフォーマットLC_TIME
: 日付/時刻のフォーマットLC_MESSAGES
: エラーとそのほかのメッセージこれは Perl 自身によって、$! と $^E 経由でオペレーティングシステムの エラーメッセージにアクセスするためだけに使われています。
LC_COLLATE
: 照合これは比較とソートのための文字の順序を示します。 例えば、ラテンアルファベットなら、"b" は一般的に "a" の次です。
LC_CTYPE
: 文字型これは、例えば、文字が大文字かどうかを示します。
一部のプラットフォームでは、長さの単位や紙のサイズといったものを扱う その他のカテゴリを持っています。 これらはどれも Perl が直接使うことはありませんが、Perl が相互作用する 外側の操作ではこれらを使うかもしれません。 後述する "Not within the scope of any "use locale" variant" を 参照してください。
Perl で使われるカテゴリに関するさらなる詳細については後述する "LOCALE CATEGORIES" を参照してください。
全体として、これらのカテゴリは単一のプログラムが複数の異なった場所で 実行するようにカスタマイズするために役立ちます。 しかし欠陥があるので、読み進めてください。
Perl 自身は、特に要求されない限りロケールを使いません (しかし再び、Perl は これらを使うコードと相互作用するかもしれません)。 たとえそのような要求があっても、正しく動作するには 以下の すべて が真になっていなければなりません:
あなたの使っているオペレーティングシステムがロケールシステムに 対応していなければなりません。 これに対応していれば、setlocale()
という関数が C ライブラリの中に あるはずです。
あなたの使うロケールの定義がインストールされていなければなりません。 あなた、もしくは管理者はこれを正しく取り扱わねばなりません。 使うことのできるロケール、それらが置かれている場所、インストールされる 規則といったものシステム毎に変わります。 一部のシステムでは、固定のほんの少しのロケールだけを提供し、ユーザーが 新たに追加することを許していません。 また、システムのサプライヤーが提供した「準備された」ロケールを 追加することができるシステムもあります。 さらに、ユーザーやシステム管理者が任意のロケールを定義して追加できる システムもあります。 (あなたのサプライヤーに使っているオペレーティング システムと一緒に渡されていない準備されたロケールを提供するよう 依頼する必要があるかもしれません。) 詳細はシステムのドキュメントを読んでください。
Perl が、ロケールシステムがサポートされていると信じていなければ なりません。 もしそうなっていれば、perl -V:d_setlocale
は d_setlocale
の値が定義されているように報告するでしょう。
Perl アプリケーションをあなたの使うデータを特定のロケールで処理したり するようにしたいのであれば、そのアプリケーションコードはプラグマ use locale
を適切な場所に、そして以下に挙げる項目の 少なくとも一つ が真でなければなりません。
あなた自身でやるにしろ、あなたの使うシステムの管理者がするにしろ、 アプリケーションの実行開始時には ロケールを決定する環境変数 ("ENVIRONMENT" を参照)が正しく設定されていなければなりません; または
アプリケーションは、"The setlocale function" に記述されている メソッドを使う、自分用のロケールを設定しておかねばなりません。
デフォルトでは、Perl 自身は現在のロケールを無視します。 use locale
プラグマは Perl に、幾つかの操作においてカレントのロケールを 使うよう指示します。 v5.16 から、このプラグマにはオプションの引数があります:
use locale ':not_characters';
(v5.20 以降ではそれほど有用ではなくなりましたが)この引数により、ロケールと Unicode をよりよく混ぜられるようになり、(完全な記述は "Unicode and UTF-8" に ありますが)簡単に言うと、ロケール定義のうち文字に関する部分、つまり LC_CTYPE
と LC_COLLATE
カテゴリを使わないように指示します。 代わりにこれは(Unicode によって拡張された)ネイティブな文字集合を使います。 この引数を使うとき、外部文字集合をネイティブ / Unicode のものに変換するのは あなたの責任です(それが徐々に有名になっている UTF-8 ロケールならこれは すでに行われています)。 "Unicode and UTF-8" に記述されているように、これを行うための便利な方法が あります。
現在のロケールは、後述する setlocale() 関数によって実行時に設定されます。 プログラム実行の過程でこの関数がまだ呼び出されていないとき、現在の ロケールはプログラムの開始時に有効な "ENVIRONMENT" によって 決定されます。 有効な環境がない場合、現在のロケールはシステムデフォルトとして 設定されたものとなります。 POSIX システムでは、これは、おそらく "C" ロケールになりますが、かならず そうとは限りません。 Windows ではデフォルトはコンピュータの コントロールパネル->地域と言語
(または現在の等価物)経由で 設定されます。
ロケールによって影響を受ける処理は:
"use locale"
variant次のように、Perl の外側を元とする操作のみが影響を受けます:
変数 $! (およびその同義語 $ERRNO
と $OS_ERROR
) と $^E (およびその同義語 $EXTENDED_OS_ERROR
) は 文字列として使われると常に現在のロケールに従い、 "use bytes" のスコープ内にあるかのように振る舞います。 これは Perl v5.22 で変更予定です。
現在のロケールは、system() や qx// のような操作によって Perl の 外側に行く場合(その操作がロケールを認識する場合)にも使われます。
また、Perl は POSIX モジュールを通して様々な C ライブラリ関数への アクセスを提供します。 これらの関数の一部は常に現在のロケールの影響を受けます。 例えば、POSIX::strftime()
は LC_TIME
を使います; POSIX::strtod()
は LC_NUMERIC
を使います; POSIX::strcoll()
と POSIX::strxfrm()
は LC_COLLATE
を使います; POSIX::isalnum()
のような文字分類関数は LC_CTYPE
を使います。 これら全ての関数は、例えロケールが Perl 空間に露出していなくても、 現在の基となるロケールに従って振る舞います。
LC_NUMERIC
以外の全てのカテゴリに関する XS モジュールは基となる ロケールを使うので、呼び出した C ライブラリ関数は基となるロケールを使います。 さらなる議論については "CAVEATS" in perlxs を参照してください。
use locale
use locale
系のスコープ内で設定される一部の Perl 操作は、 スコープの外側でも影響を受けたままになります。 これには以下のようなものがあります:
write() の出力形式は、事前のフォーマット宣言 ("format" in perlfunc) によって決定されるので、出力がロケールの影響を 受けるかどうかは、format()
は use locale
系のスコープ内にあるかどうかで 決定され、write()
ではありません。
正規表現パターンは、 qr// を使って、 実際のマッチングを後に遅らせてコンパイルすることが出来ます。 再び、コンパイルが use locale
のスコープ内で行われたかどうかが マッチングの振る舞いを決定します; スコープ内でマッチングが 行われたかどうかではありません。
"use locale ':not_characters';"
非 Perl 操作全て。
フォーマット宣言 ("format" in perlfunc) と引き続く write()
は LC_NUMERIC
を使います。
文字列化と出力 は LC_NUMERIC
を使います。 これらには print()
, printf()
, say()
, sprintf()
の結果が含まれます。
"use locale";
前述の操作全て
比較演算子 (lt
, le
, cmp
, ge
, gt
) は LC_COLLATE
を 使用します。 sort()
は比較関数が陽に指定されなかった場合に影響を受けます; これは、 デフォルトでは cmp
を使うからです。
注意: eq
および ne
はロケールの影響を受けません: これらの関数は常に 文字毎の比較をそのスカラオペランドに対して実行します。 それに加えて、cmp
はそのオペランドがカレントのロケールで 指定される照合シーケンスで等しいものであった場合、さらに文字毎の 照合を行おうします; そして、オペランドの全部の文字が等しい場合にのみ cmp
は 0(等しい)を返します。 eq
と cmp
が異なると判定する可能性のある二つの文字列がロケールを 考慮した照合で等しいかどうかを本当に知りたいのなら、 "Category LC_COLLATE
: Collation" の記述を参照してください。
正規表現と大小文字変換関数 (uc()
, lc()
, ucfirst()
, lcfirst()
) は LC_CTYPE
を使用します。
no locale
に出会うか、(use locale
を囲む)ブロックの終端に 達するとデフォルトの動作に戻ります。 use locale
と use locale ':not_characters'
はネストしているかもしれず、 内側のスコープで有効だったものが内側のスコープの終了によって外側のスコープの 規則に差し戻されることに注意してください。
ロケール情報を使っている操作の結果である文字列は、ロケールが信頼できない 可能性があるかのように、汚染されていることに注意してください。 "SECURITY" を参照してください。
POSIX::setlocale()
関数を使って、実行時に好きな回数だけロケールを 切り替えることができます。
# Import locale-handling tool set from POSIX module.
# This example uses: setlocale -- the function call
# LC_CTYPE -- explained below
# (Showing the testing for success/failure of operations is
# omitted in these examples to avoid distracting from the main
# point)
use POSIX qw(locale_h);
use locale;
my $old_locale;
# query and save the old locale
$old_locale = setlocale(LC_CTYPE);
setlocale(LC_CTYPE, "fr_CA.ISO8859-1");
# LC_CTYPE now in locale "French, Canada, codeset ISO 8859-1"
setlocale(LC_CTYPE, "");
# LC_CTYPE now reset to the default defined by the
# LC_ALL/LC_CTYPE/LANG environment variables, or to the system
# default. See below for documentation.
# restore the old locale
setlocale(LC_CTYPE, $old_locale);
setlocale()
の第一引数には カテゴリ を、第二引数には ロケール を与えます。 カテゴリはロケール特有の規則を適用したいデータ処理の状況を指示します。 カテゴリ名は "LOCALE CATEGORIES" と "ENVIRONMENT" に記述されています。 ロケールはカスタマイズを行うための、特定の言語の組み合わせ、国や地域、 コードセットに関する情報の集合の名前です。 ヒントとしてロケールの名前付けに注目してください: すべてのシステムが この例のようにロケールに名前を付けているわけではありません。
第二引数が省略されていて、さらにカテゴリが LC_ALL
以外の場合、この関数は カテゴリに対するカレントロケールの名前からなる文字列を返します。 この値を、後で行う setlocale() の呼び出しでの第二引数として 使うこともできます が 一部のプラットフォームでは文字列は不明瞭で、 ほとんどの人にとってどのロケールのことか解読できるようなものではありません。
カテゴリが LC_ALL
で、第二引数が与えられなかった場合には その結果は処理系に依存するものとなります。 ロケールの名前を連結したものか(セパレーターはこれまた処理系依存のもの)、 単一のロケール名となります。 詳しくは setlocale(3) man ページをあたってください。
第二引数が与えられていて、かつそれが正当なものであれば、カテゴリの ロケールが設定され、この関数は現在のロケール値を返します。 この値は次の setlocale()
に呼び出しで使えます。 (一部の実装では、この返り値は第二引数を与えたときと異なる場合があります -- これは与えた引数のエイリアスと考えられます。)
例に示したように、第二引数が空文字列であった場合にはカテゴリの、 対応する環境変数によりデフォルト指定されるロケールが返されます。 一般的にはこの結果は、Perl が起動したときに強制的にデフォルトとして 設定された値です: アプリケーションが起動した後での環境変数の変更が 認識される/されないは、使用している C ライブラリに依存します。
Perl は use locale ':not_characters'
のスコープの内側では現在の LC_CTYPE
ロケールと LC_COLLATE
ロケールを無視することに 注意してください。
何らかの理由 (例えばシステムが知らないロケールを設定しようとした) で set_locale()
が失敗した場合、カテゴリに対するロケールは変更されず、関数は undef
を返します。
カテゴリに対する詳細な情報は、setlocale(3) を参照してください。
ロケールが使えるシステムであれば、使用可能なロケールがどういったもので あるかどうかを setlocale(3) で調べてみてください (SEE ALSO の章を探してください)。 それがダメだったら、以下のコマンドを試してみてください。
locale -a
nlsinfo
ls /usr/lib/nls/loc
ls /usr/lib/locale
ls /usr/lib/nls
ls /usr/share/locale
そして、そこに以下に挙げたものと似たものがあるかどうかを 確かめてください。
en_US.ISO8859-1 de_DE.ISO8859-1 ru_RU.ISO8859-5
en_US.iso88591 de_DE.iso88591 ru_RU.iso88595
en_US de_DE ru_RU
en de ru
english german russian
english.iso88591 german.iso88591 russian.iso88595
english.roman8 russian.koi8r
残念ながら、setlocale()
を呼び出すインターフェースが既に 標準化されているのにも関らず、ロケールの名前や、それが設定される ディレクトリはまだなのです。 名前の基本形式は language_territory.codeset ですが、末尾の部分は 常にある訳ではありません。 language と country は通常は ISO 3166 や ISO 639 という 標準による、言語や国を二文字に略したものになります。 codeset の部分はしばしば文字集合 ISO 8859 の バリエーションとなります。 たとえば、"Western codeset" と呼ばれる ISO 8859-1
は西欧における エンコーディングとして用いることができます。 繰り返しますが、一つの標準の名前であってさえ、記述するには複数の方法が 存在するのです。 嘆かわしいことです。
"C" と "POSIX" という二つの特殊なロケールがあります。 現時点では、これら二つは同じロケールとなります。 その違いは主に、前者が C の標準により決められたものであるのに対して、 後者が POSIX の標準で決められているものであるという点にあります。 これらの規格が決めていることは、環境変数にあるロケール情報がない状態での プログラム起動時の デフォルトのロケール です (デフォルトの デフォルトロケールです)。 その言語は (アメリカ)英語であり、その文字集合は ASCII か、稀に ("DEC Multinational Character Set (DEC-MCS)" のような)その上位集合になります。 警告。 一部のベンダによって提供されている C ロケールは実際には C 標準が要求している ものに正確に一致していないかもしれません。 注意してください。
注意:すべてのシステムが "POSIX" ロケールを持っているわけでは ありません(すべてのシステムが POSIX に準拠しているわけではありません)ので、 明示的にこのデフォルトロケールを指定するのが必要なときには "C" を使います。
Perl を実行したときに以下のようなメッセージを見たことがあるかもしれません:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LC_ALL = "En_US",
LANG = (unset)
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
これは、あなたのロケールの設定が、LC_ALL
が "En_US" であり LANG が 存在しているが値を持っていないということを意味します。 Perlはあなたを信じようとしたのですができなかったのです。 その代わりに、Perl はロケール設定をあきらめて、デフォルトである "C" ロケールに戻ったのです。 (Windows では、まずシステムのデフォルトロケールにフォールバックすることを 試みます。) これは通常はあなたのロケール設定が間違っているせいであり、聞いたことのない ロケールであったり、あるいはあなたのインストールに問題があったのだろう (例えば、一部のシステムファイルが壊れていたとか、なかったとか)と いうことです。 以下で述べるのは、この問題を手っ取り早く一時的に修復するものです。
Perl をソースからビルドする場合、Perl テストスイートファイル lib/locale.t がシステムのロケールのテストに使われます。 環境変数 PERL_DEBUG_FULL_TEST
を 1 に設定すると、詳細な結果を出力します。 例えば、Linux では、以下のようにします:
PERL_DEBUG_FULL_TEST=1 ./perl -T -Ilib lib/locale.t > locale.log 2>&1
その他の多くのテストに加えて、システムで発見された全てのロケールについて POSIX 標準に従っているかどうかをテストします。 エラーがあった場合、どのロケールが全てのテストに成功したかの出力の末尾辺りに、 どのテストがなぜ失敗したかの概要が含まれます。
二つの(一時的な)対応策とは、ロケールに関する矛盾を無視するように するというものと、Perl をデフォルトロケール "C" で実行するというものです。
Perl 起動時の問題は、環境変数 PERL_BADLANG
にゼロの値、たとえば "0" を設定することによって回避できます。 この方法は問題をカーペットの下に押し込むだけのことです: つまり、Perl が何か間違ったことを見つけたとしても Perl を 黙らせておくというものです。 もし後でロケールに依存した変な振る舞いがあったとしても 驚かないでください。
環境変数 LC_ALL
に "C" を設定することにより、Perl はロケール "C" の下でも 実行することができます。 このやり方は PERL_BADLANG
よりは多少まともなものですが、それでも LC_ALL
(もしくは他のロケール変数)を設定するということは Perl 以外の プログラムにも影響を及ぼします。 特に、Perl の内側で実行される外部プログラムはこの変更に影響を 受けることになります。 新しい設定を恒久的なものにしたいというのであれば、あなたが実行する プログラム全てがこの変更に影響を受けることになります。 関係する環境変数の完全なリストは "ENVIRONMENT" を参照してください; また、Perl におけるそれらの効果については "USING LOCALES" を 参照してください。 他のプログラムに対する影響は簡単に避けられます。 たとえば、変数 LC_COLLATE
はあなたの sort プログラム (もしくは「レコード」をアルファベット順に並べ替えるプログラム)に 影響を及ぼします。
これらの変数に対する変更を一時的に行ってテストすることができます; そして 新しい設定が助けになるものであればその設定をシェルのスタートアップ ファイルに追加するのです。 詳細はあなたの使っているシステムのドキュメントを調べてみてください。 Bourne シェルに似たシェル(sh, ksh, bash, zsh)であれば 以下のようになります:
LC_ALL=en_US.ISO8859-1
export LC_ALL
これは、コマンドが参照するロケールを "en_US.ISO8859-1" にしています。 Cシェルライクなもの(csh, tcsh)の場合には以下のようになります:
setenv LC_ALL en_US.ISO8859-1
あるいは、"env" プログラムがあるなら、どのようなシェルでも、以下のように 書けます:
env LC_ALL=en_US.ISO8859-1 perl ...
あなたがシェルについて良く知らないというのであれば、 あなたのおそばのヘルプデスク等に訊ねてみてください。
時間はかかるけれども優れた修正方法は、あなたの環境の間違っている部分を 正しくするというものです。 システム全体での間違いはあなたの使っているシステムの、フレンドリーな 管理者の助けを必要とするでしょう。
まず最初にこのドキュメントの "Finding locales" を参照してください。 そこにはあなたの使うシステムで実際にサポートされているロケール、 そしてもっと重要なインストールされているロケールを見つけだす方法が 解説されています。 私たちが使ったエラーメッセージの例では、環境変数は重要度の高いものから 低いものへという順になっています。 したがって、LC_ALL を "En_US" に設定することは良くない選択であり、 これはエラーメッセージにも現れています。 まず最初にリストの最初にあるロケール設定を修正します。
次に、もしあなたがリストアップのコマンドを使って得たものが 正確に "En_US" のようなもの(接頭辞の一致は考慮せず、大小文字の違いは 考慮します)であれば、あなたが使っているロケール名に対応するものが システムに正しくインストールされていれば OK です。 この場合、"Permanently fixing your system's locale configuration" を 参照してください。
これは以下のようなメッセージが出たけれども:
perl: warning: Please check that your locale settings:
LC_ALL = "En_US",
LANG = (unset)
are supported and installed on your system.
"En_US" が先に挙げたコマンドによってリスト中になかった場合です。 "en_US.ISO8859-1" のようなものを見たかも知れませんが、まったく 同一のものではなかったのでしょう。 この場合、コマンドで挙げられたもの一致するロケールで 実行してみてください。 ロケール名のマッチングルールは少々はっきりしないものです; それは、この分野に 関する標準が弱いものであるからです。 一般的なルールについては "Finding locales" をもう一度見てください。
システム管理者にコンタクトをとって、あなたの得たエラーメッセージそのままを レポートして、今ここまで読んできたことを説明してください。 システム管理者はシステムのロケール設定についてどこがどう間違っているかを 理解できるはずです。 標準化がなされていないので、コマンド名などに関して "Finding locales" の 章は残念ながら少々あやふやなものになっています。
POSIX::localeconv()
関数は、カレントの LC_NUMERIC
や LC_MONETARY
で 指定されるロケール依存の数値書式の情報を取り出します。 (ある特定のカテゴリのカレントロケールを知りたいだけなのなら、 POSIX::setlocale()
を引数一つで使います--"The setlocale function" を 参照してください。)
use POSIX qw(locale_h);
# Get a reference to a hash of locale-dependent info
$locale_values = localeconv();
# Output sorted list of the values
for (sort keys %$locale_values) {
printf "%-20s = %s\n", $_, $locale_values->{$_}
}
localeconv()
は引数を取らず、戻り値としてハッシュに対する リファレンス を返します。 このハッシュのキーは decimal_point
や thousands_sep
のように 整形された変数名です。 格納されている値はそのキーに対応する値です。 ある実装が提供しているであろうすべてのカテゴリをリストアップしている 長いサンプルは "localeconv" in POSIX を参照してください; しかしながら、一部のものが多かったり少なかったするかもしれません。 ロケールを問い合わせるジョブの関数のように use locale
する必要が ないことに注意してください; localeconv()
は常にカレントのロケールを 監視しています。
以下の例は、コマンドラインで渡されたパラメーターをカレントのロケールにおける 正しい書式に書きなおすというものです。
use POSIX qw(locale_h);
# Get some of locale's numeric formatting parameters
my ($thousands_sep, $grouping) =
@{localeconv()}{'thousands_sep', 'grouping'};
# Apply defaults if values are missing
$thousands_sep = ',' unless $thousands_sep;
# grouping と mon_grouping は小整数のパック済みリストになって
# います; これはgrouping (thousand_seps と mon_thousand_seps
# はグループを分けるものです)の数と金銭に関するものの指定を
# 行っています。その整数の意味はこうです: 255はグルーピング
# しないことを意味します; 1から254はカレントのグルーピングで
# 使用する数値を意味します;。グルーピングは右から左へ(下位桁から
# 上位桁)と適用されます。下の例では最初のグルーピング以外は
# (それが何でも)使わないことによってこれを避けています。
if ($grouping) {
@grouping = unpack("C*", $grouping);
} else {
@grouping = (3);
}
# Format command line params for current locale
for (@ARGV) {
$_ = int; # Chop non-integer part
1 while
s/(\d)(\d{$grouping[0]}($|$thousands_sep))/$1$thousands_sep$2/;
print "$_";
}
print "\n";
ロケール依存の情報を問い合わせるその他のインターフェースとしては I18N::Langinfo::langinfo()
関数があり、少なくとも Unix 風のシステムと VMS で利用可能です。
以下の例は langinfo()
関数自身と、langinfo()
の引数として使う 3 つの 定数をインポートします: 1 つは現在のロケールでの週の最初の日の省略形 (番号は日曜日=1として振られています)、後の 2 つははい/いいえの質問に 対しての肯定および否定を現在のロケールで表すものです。
use I18N::Langinfo qw(langinfo ABDAY_1 YESSTR NOSTR);
my ($abday_1, $yesstr, $nostr)
= map { langinfo } qw(ABDAY_1 YESSTR NOSTR);
print "$abday_1? [$yesstr/$nostr] ";
言い換えると、"C" (または English) ロケールでは上記のものはおそらく 以下のようなものが表示されます:
Sun? [yes/no]
さらなる情報については I18N::Langinfo を参照してください。
以下のセクションでは、基本的なロケールカテゴリの説明をします。 先の例のように、複数の基本カテゴリを扱うことができる幾つかの 組み合わせカテゴリ(combination categories)があります。 この事に関する詳細は、"ENVIRONMENT" を参照してください。
LC_COLLATE
: 照合use locale
のスコープの内側にある(そして use locale ':not_characters'
の内側でない)とき、Perl はアプリケーションで 使用する文字の照合(順番)を決定するために環境変数 LC_COLLATE
を 参照します(ラテンアルファベットでは "b" は "a" に続くものですが、 "á" や "å" はどこに置かれるのでしょう?)。 また、英語では "color" は "chocolate" よりも後になりますが、伝統的な スペイン語ではどうでしょう?
以下の照合は全て意味あるものであり、"use locale" をすれば直面することも あるでしょう。
A B C D E a b c d e
A a B b C c D d E e
a A b B c C d D e E
a b c d e A B C D E
以下のコード片はカレントのロケールにおける英数文字をそのロケールでの 順序で出力するものです。
use locale;
print +(sort grep /\w/, map { chr } 0..255), "\n";
これと、陽にロケールを無視するように指示したときの文字とを 比較してみてください。
no locale;
print +(sort grep /\w/, map { chr } 0..255), "\n";
この、マシン本来の照合(同じブロックの前のほうで use locale
を していない方)は生のバイナリデータのソートに用いるもので、 最初の例で使ったロケール依存の照合は通常のテキストに使うのに便利です。
"USING LOCALES" で述べたように、cmp
は use locale
が有効なときには カレントの照合ロケールに従って比較を行いますが、 この結果が等しいと出た場合には文字毎の比較に逆戻りします。 この逆戻りが嫌ならば、POSIX::strcoll()
を使うことができます。
use POSIX qw(strcoll);
$equal_in_locale =
!strcoll("space and case ignored", "SpaceAndCaseIgnored");
$equal_in_locale
は照合ロケールが空白キャラクタを完全に無視し、 大小文字の区別を無視するような辞書に似た順序付けを指定している場合には 真になるでしょう。
Perl は LC_COLLATE
に関して単一バイトロケールのみに対応しています。 つまり、UTF-8 ロケールが単にマシンネイティブな順序を 提供するだろうということです。 Unicode 照合アルゴリズムに関する完全な実装については Unicode::Collate を 使ってください。
「ロケールにおける等価性」の検査を他のものに対して行いたい(一つの) 文字列があるときにあなたは、POSIX::strxfrm()
を eq
と一緒に 使うことによって多少の効率アップができると考えるかもしれません:
use POSIX qw(strxfrm);
$xfrm_string = strxfrm("Mixed-case string");
print "locale collation ignores spaces\n"
if $xfrm_string eq strxfrm("Mixed-casestring");
print "locale collation ignores hyphens\n"
if $xfrm_string eq strxfrm("Mixedcase string");
print "locale collation ignores case\n"
if $xfrm_string eq strxfrm("mixed-case string");
strxfrm()
は文字列を引数にとり、それを同様の変換を加えられた文字列との 文字毎の比較に使えるような文字列に変換します。 「フードの中では」、ロケールに影響された Perl の比較演算子は strxfrm()
を両オペランドのために呼び出して、その後で文字毎の比較を、 変換された文字列に対して行います。 strxfrm()
を陽に呼び出すこととロケールに影響されない比較を行うことで、 上記の例は変換をセーブするようになります。 実際にはこれは何もセーブしません: Perl の魔法("Magic Variables" in perlguts を 参照)は、比較の際に必要であれば最初に変換された文字列を生成し、それからそれが 再び必要になるまで取っておくのです。 cmp
を使って書き直したサンプルは可能な限り早く実行されます。 また、文字列に埋め込まれているヌル文字にも対処します; strxfrm()
を 直接呼び出した場合、ナルは終端子としてみなされます。 そして、変換後の文字列がシステムを越えて使えるようなものであると 期待してはいけません; また、あるオペレーティングシステムのバージョンで 作ったものが次の バージョンでも同様であるということも期待してはいけません。 一言でいうと、strxfrm()
を直接呼び出してはいけない、ということです: Perl に呼び出しをさせましょう。
注意: 幾つかのサンプルでは、必要がないので use locale
がありません: strcoll()
や strxfrm()
は、常に LC_COLLATE
ロケールに従う、システムが 供給する標準の libc
関数を使う POSIX 関数です。
LC_CTYPE
: 文字タイプuse locale
のスコープにある(そして use locale ':not_characters'
の 内側でない)とき、Perl は LC_CTYPE
ロケールの設定に従います。 これは、アプリケーションの英字、数字、句読点 など かどうかの扱いを 制御します。 これは、英数字 -- つまり、英字、数字、およびプラットフォームのネイティブな 下線を含みます --に関わる正規表現のメタ表記 \w
に影響します。 (正規表現に関するさらなる情報については perlre を参照してください)。 LC_CTYPE
のおかげで、ロケール設定に依存した "æ", "ð", "ß", "ø" のような文字が \w
文字として認識できるのです。 これはまた \s
, \D
および [[:graph:]]
のような POSIX 文字クラスにも 影響を与えます。 (これら全てに関するさらなる情報については perlrecharclass を 参照してください。)
LC_CTYPE
ロケールはまた、小文字と大文字との間の相互変換に使われる マッピングを提供します。 これは大文字小文字変換関数 fc()
, lc()
, lcfirst()
, uc()
, ucfirst()
とダブルクォートで囲まれた文字列の中での \F
, \l
, \L
, \u
, <\U> による大文字小文字変換、そして s///
による置換、 i
修飾子を使った(大小文字を無視する)正規表現パターンマッチングに 影響を及ぼします。
さらに、LC_CTYPE
は (廃止予定の) POSIX のキャラクタクラステスト関数 POSIX::isalpha()
, POSIX::islower()
などにも影響を及ぼします。 たとえば、"C" ロケールを 7 ビットのスカンジナビアのものにしたとすると、 多分あなたは驚くことになるでしょうが、"|" が POSIX::ispunct()
クラスから POSIX::isalpha()
クラスに移動するのです。 残念ながら、これは正規表現に関して大きな問題を起こします。 "|" は、たとえ \w
にマッチングしても代替を意味したままです。
v5.20 から、Perl は LC_CTYPE
に関して LC_CTYPE
に対応していますが、 それ以外では Perl は ISO 8859 シリーズのような単一バイトロケールのみに 対応しています。 これはつまり、アジア言語のようなワイド文字ロケールには 対応していないということです。 UTF-8 ロケール対応は実際には POSIX ロケールの上位集合です; ロケールの影響を一切受けない完全な Unicode の振る舞いだからです (例外は汚染です; "SECURITY" を参照してください)。 POSIX ロケールは、例え UTF-8 のものでも、 文字の大文字小文字の変更が複数文字に拡張されるような、 Unicode のいくつかの概念が欠けています。 UTF-8 ロケールでは、Perl は拡張を提供します。 UTF-8 ロケールについて、v5.20 より前の Perl では、 一部のプラットフォームではある種の制限付きの ISO 8859-1 として扱い、 その他のプラットフォームではより "C" ロケールに近いものになります。 リリース v5.16 と v5.18 では、use locale 'not_characters
が これの回避策として使われていました ("Unicode and UTF-8" を 参照してください)。
現在のロケールによって影響を受けないものもいくつかあることに注意してください。 例えば \n
のような、特定の文字のためのエスケープシーケンス全ては、常に プラットフォームにネイティブなものを意味します。 つまり、例えば、正規表現中の \N
(改行以外の全ての文字) はプラットフォームの 文字集合に対して動作します。
注意: 壊れた、あるいは悪意のある LC_CTYPE
ロケールの定義は、 不適切な文字を英数字であるとみなしてしまう可能性があります。 (アクセント記号のない)文字や数字の厳密なマッチング、例えばコマンド文字列の ロケールを気にするアプリケーションは /a
正規表現修飾子付きで \w
を使うべきです。 "SECURITY" を参照してください。
LC_NUMERIC
: 数値形式適切な POSIX::setlocale()
呼び出しの後、use locale
系の一つのスコープの 内側では、Perl は LC_NUMERIC
ロケール情報を参照します; これは アプリケーションが数値をどのように整形するかということを制御するものです。 大部分の実装では、小数点を表わす文字を "." から "," へと 変更するだけの効果しかありません。 この関数は三桁毎の区切りなどについては考慮しません。 (この事について心配があるのなら "The localeconv function" を 参照してください。)
use POSIX qw(strtod setlocale LC_NUMERIC);
use locale;
setlocale LC_NUMERIC, "";
$n = 5/2; # Assign numeric 2.5 to $n
$a = " $n"; # Locale-dependent conversion to string
print "half five is $n\n"; # Locale-dependent output
printf "half five is %g\n", $n; # Locale-dependent output
print "DECIMAL POINT IS COMMA\n"
if $n == (strtod("2,5"))[0]; # Locale-dependent conversion
I18N::Langinfo と RADIXCHAR
も参照してください。
LC_MONETARY
: 金銭の書式標準 C では LC_MONETARY
カテゴリを定義していますが、その内容に 影響される関数はありません。 (規格委員会の経験によって、それらはワーキンググループがこの問題を 蹴り出すことに決めたことを認識したのでしょう。) 結果として、Perl は基本的にこれに注意を払いません。 もし本当に LC_MONETARY
を使いたければ、自分でその内容を 問い合わせることができます("The localeconv function" を参照してください); そして返ってきた情報をアプリケーションの通貨量の整形に使います。 しかし、この情報を取得することはできるでしょうが、大量かつ複雑で、 要求に対して本当にあったものではないでしょう: 金銭に関する書式は手に おえない代物なのです。
I18N::Langinfo と CRNCYSTR
も参照してください。
LC_TIME
人が読みやすい、整形された日付/時刻文字列を作り出す POSIX::strftime()
によって生成された出力はカレントの LC_TIME
ロケールに 影響を受けます。 したがって、フランスのロケールでは、%B
書式指定子(省略のない月の名前)を 一年の最初の月に対して使ったときの結果は、"janvier" となります。 以下の例は、カレントロケールにおける長い月名のリストを得るものです。
use POSIX qw(strftime);
for (0..11) {
$long_month_name[$_] =
strftime("%B", 0, 0, 0, 1, $_, 96);
}
注意: use locale
はこの例では必要ではありません: strftime()
は POSIX 関数で、標準のシステムが供給する libc
関数を使い、常に カレントの LC_TIME
ロケールを参照します。
I18N::Langinfo と ABDAY_1
..ABDAY_7
, DAY_1
..DAY_7
と ABMON_1
..ABMON_12
と ABMON_1
..ABMON_12
も参照してください。
残ったロケールカテゴリは現在のところ Perl 自身では使われません。 しかし再び、標準の Perl 配布 パッケージにはない拡張モジュールや OS やそのユーティリティなど、Perl が 相互作用するものがこれらを使うかも知れないことに注意してください。 $!
の文字列値と、外部のユーティリティから与えられたエラーメッセージは LC_MESSAGES
で変更されているかもしれないことに特に注意してください。 移植性のあるエラーコードがほしい場合は、%!
を使ってください。 Errno を参照してください。
Perl のセキュリティに関する事項の主な議論は perlsec にありますが、 Perl のロケールの扱いに関する議論はそれがあなたのロケール依存の セキュリティ事項に対して注意していなければ不完全です。 ロケールは(特に特権のないユーザーが自分のロケールを構築するのを許すような システムでは)信用できないものなのです。 悪意のある(もしくは単に壊れた)ロケールはロケールを使うアプリケーションを 予期できない結果にする可能性があります。 以下に幾つかの可能性を挙げます。
安全なファイル名やメイルアドレスを検索するための正規表現で \w
を使うと、 ">" や "|" を英数字と主張するような LC_CTYPE
に だまされてしまう可能性があります。
$dest = "C:\U$name.$ext"
のような、大文字小文字変換を伴った文字列の改変は、 不正な LC_CTYPE
の大文字小文字変換テーブルが有効であるときに 危険な結果を生成する可能性があります。
陰険な LC_COLLATE
ロケールは "D" 等級の生徒の名前を "A" の前に置いてしまう結果にさせるかもしれません。
手間を惜しまずに LC_MONETARY
にある情報を使うアプリケーションは、 ロケールがおかしいと、負債を預金のように扱ったり、その逆にしたり してしまうかもしれません。 あるいは、香港ドルの代わりに US ドルで支払いをさせたりしてしまうかも しれません。
strftime()
により整形された日付情報は、LC_DATE
をいじりまわすことの できる悪意あるユーザーにより操作されてしまう可能性があります。 (「見てくれよ、こいつ俺が日曜日にビルディングにいなかったって 言ってるよ。」)
このような危険は、ロケールシステムに特有のものではありません: 意地の悪い 変更を通して同じような攻撃を受けるようなアプリケーション環境の あらゆる状況が対象となります。 同様に、これは Perl に固有なものでもありません: 環境を考慮するような プログラムを書くことのできるあらゆるプログラミング言語で同様の危険性が あるのです。
perlは例示したようなすべての可能性からあなたを守ることはできません-- あなた自身の用心に代り得るものはないのです--しかし、use locale
が 有効であるとき、Perl は汚染チェック機構(perlsec を参照)を、ロケールに 依存した結果であり、信用できないかもしれない文字列に注意するために 使用します。 以下は、ロケールにより影響を受ける可能性のある演算子や関数の汚染される 振る舞いのまとめです。
比較演算子 (lt
, le
, ge
, gt
, cmp
):
スカラの真/偽(もしくは未満/等しい/越えている)の結果は 決して汚染されません。
大文字小文字変換 (\l
, \L
, \u
, \U
, \F
)
展開されたものが含まれる文字列は use locale
が有効な (そして use locale ':not_characters'
が有効でない) 場合には汚染されます。
マッチング演算子 (m//
):
スカラの真/偽の結果は決して汚染されません。
リストコンテキストの結果や、$1
など として渡される全てのサブパターンは、 use locale
が有効である (そして use locale ':not_characters'
が 有効でない) かつ正規表現サブパターンにロケール依存の構文を含んでいるときには 汚染されます。 これらの構文には \w
(英数字にマッチングする)、\W
(英数字以外にマッチングする)、 \b
と \B
(単語境界と非単語境界; \w
と \W
がマッチングするものに 依存する)、\s
(空白文字)、\S
(空白文字以外)、 \d
と \D
(数字と非数字)、[:alpha:]
のような POSIX 文字クラス ("POSIX Character Classes" in perlrecharclass 参照) が含まれます。
パターンが (/i
を使って) 大文字小文字を無視してマッチングするような ものである場合、おそらく汚染も起こります。 例外は、この方法でマッチングする全ての符号位置が 255 より大きく、 Unicode の規則の基で 256 より小さいものに畳み込みが行われない場合です。 これらについては汚染は起こりません; なぜなら Perl はこのような符号位置に 対しては Unicode の規則のみを使い、この規則は現在のロケールに関わらず 同じだからです。
マッチした結果を保持する変数、$&
,、$`
(マッチした部分より前)、 $'
(マッチした部分より後)、$+
(最後にマッチしたもの)も汚染されます。
置換演算子 (s///
):
マッチング演算子と同じ振る舞いをします。 また、=~
の左側のオペランドは、use locale
が有効の (そして use locale ':not_characters'
が 有効でない)とき、 前に言及したもの、または \l
, \L
,\u
, \U
, \F
のような大文字小文字変換によって 値が変更された場合、汚染されます。
出力書式関数 (printf()
と write()
):
結果は決して汚染されません; なぜなら、もしそうでないなら、 例えば print(1/7)
のような、print からの出力ですら use locale
が有効のときは汚染されることになってしまいます。
大文字小文字変換関数 (lc()
, lcfirst()
, uc()
, ucfirst()
):
use locale
が有効な(そして use locale ':not_characters'
が 有効でない)ときに、結果が汚染されます。
POSIX ロケール依存関数 (localeconv()
, strcoll()
, strftime()
, strxfrm()
):
結果は決して汚染されません。
POSIX 文字クラステスト (POSIX::isalnum()
, POSIX::isalpha()
, POSIX::isdigit()
, POSIX::isgraph()
, POSIX::islower()
, POSIX::isprint()
, POSIX::ispunct()
, POSIX::isspace()
, POSIX::isupper()
, POSIX::isxdigit()
):
真/偽の結果は決して汚染されません。
三つの例を使って、ロケール依存の汚染を説明します。 最初のプログラムはそのロケールを無視して、実行されません: 汚染検査が 有効であるときには、コマンドラインから直接とった値を出力ファイル名として 使うことはできません。
#/usr/local/bin/perl -T
# Run with taint checking
# Command line sanity check omitted...
$tainted_output_file = shift;
open(F, ">$tainted_output_file")
or warn "Open of $tainted_output_file failed: $!\n";
このプログラムは、汚染された値を正規表現を通して 「洗浄」(laundering)することにより実行できるようにできます: 以下に挙げる二番目の例は--これもロケール情報を無視しています-- 実行されると、コマンドラインにある名前のファイルを可能であれば作成します。
#/usr/local/bin/perl -T
$tainted_output_file = shift;
$tainted_output_file =~ m%[\w/]+%;
$untainted_output_file = $&;
open(F, ">$untainted_output_file")
or warn "Open of $untainted_output_file failed: $!\n";
これを、非常に良く似てはいますが、ロケールを使ったプログラムと 比較してみてください。
#/usr/local/bin/perl -T
$tainted_output_file = shift;
use locale;
$tainted_output_file =~ m%[\w/]+%;
$localized_output_file = $&;
open(F, ">$localized_output_file")
or warn "Open of $localized_output_file failed: $!\n";
この三番目のプログラムは、$&
が汚染されているので実行に失敗します; これは use locale
が有効であるときの \w
を含んだマッチングによる 結果です。
この環境変数は Perl v5.20 から利用可能で、これが真の値に評価される場合、 初期化のためのその他の環境変数を使わないように Perl に伝えます。 代わりに、Perl は現在のロケール設定を使います。 これは組み込み環境で特に有用です; "Using embedded Perl with POSIX locales" in perlembed を参照してください。
Perl が起動時にロケールの設定に失敗した場合に警告を出すのを抑制できる 文字列です。 オペレーティングシステムのロケールサポートがなんらかの理由でなかったり、 壊れていたりするとき、あるいは環境変数に設定したロケールの名前を 間違えていた場合に発生します。 もしこの変数が存在していないとか、あるいはその値が評価すると0に ならないようなもの、つまり "0" や "" でない場合に、Perl はロケールの設定に 失敗するとメッセージを出力します。
注意: PERL_BADLANG
は警告メッセージを出さないようにするだけです。 このメッセージはあなたの使うシステムのロケールサポートになにかの問題が あるということを伝えるものですから、あなたは問題が何なのかを 確かめるべきでしょう。
以下の環境変数は Perl に特有のものではなく、アプリケーションのデータの 扱いを制御するための標準的な(ISO C, XPG4, POSIX 1.c) setlocale()
メソッドの 一部分です。 Windows は POSIX ではありませんが、Perl はそれでもここで記したとおりに 動作するように用意します。 環境変数で与えられたロケールが正当ではない場合、 優先順位で次のものを使おうとします。 Windows では、正当なものがない場合、システムデフォルトロケールを 使おうとします。 全てに失敗した場合、"C"
ロケールが使われます。 これすらも動作しない場合、何かがひどく壊れていますが、 Perl は何かロケール設定があるものとして前に進もうとします。
LC_ALL
LC_ALL
は「全て上書き」ロケール環境変数です。 もしこの環境変数が設定されていると、他のすべての環境変数を上書きします。
LANGUAGE
注意: LANGUAGE
は GNU の拡張で、GNU libc を使っているときにのみ 効果があります。 Linux を使ったときなどがこれに該当します。 あなたが「商用の」Unix を使っているのであれば GNU libc は 使われていないでしょうし、LANGUAGE
は無視することができます。
LANGUAGE
を使った場合には、コマンドからの情報、警告、エラーといった メッセージの言語に影響を及ぼします(言い換えると LC_MESSAGES
と 似ています)が、LC_ALL
よりも優先順位は下です。 さらに、これは単一の値ではなくて言語(ロケールではありません)の、 ":" で連結された「パス」になっています。 より詳しい情報は GNU gettext
ライブラリのドキュメントを参照してください。
LC_CTYPE
.LC_ALL
がないときに、LC_CTYPE
は文字タイプのロケールを選択します。 LC_ALL
と LC_CTYPE
の両方ともない場合、LANG
が文字タイプの ロケールを選択します。
LC_COLLATE
LC_ALL
がないときに、LC_COLLATE
は照合(ソート)ロケールを選択します。 LC_ALL
と LC_COLLATE
の両方ともない場合、LANG
が 照合ロケールを選択します。
LC_MONETARY
LC_ALL
がないときに、LC_MONETARY
は通貨形式ロケールを選択します。 LC_ALL
と LC_MONETARY
の両方ともない場合、 LANG
が通貨形式ロケールを選択します。
LC_NUMERIC
LC_ALL
がないときに、LC_NUMERIC
は数値表記のロケールを選択します。 LC_ALL
と LC_NUMERIC
の両方ともない場合、LANG
が数値表記を 選択します。
LC_TIME
LC_ALL
がないときに、LC_TIME
は日付・時刻表記のロケールを選択します。 LC_ALL
と LC_TIME
の両方ともない場合、LANG
が日付・時刻表記の ロケールを選択します。
LANG
LANG
は「包括的」なロケール環境変数です。 これに値が設定されている場合、LC_ALL
も、各カテゴリの LC_foo
も 設定されていないときの最後の参照場所として使われます。
LC_NUMERIC
は数値出力を制御します:
use locale;
use POSIX qw(locale_h); # Imports setlocale() and the LC_ constants.
setlocale(LC_NUMERIC, "fr_FR") or die "Pardon";
printf "%g\n", 1.23; # If the "fr_FR" succeeded, probably shows 1,23.
そして文字列が POSIX::strtod()
によってどのように数値としてパースされるかも 制御します:
use locale;
use POSIX qw(locale_h strtod);
setlocale(LC_NUMERIC, "de_DE") or die "Entschuldigung";
my $x = strtod("2,34") + 5;
print $x, "\n"; # Probably shows 7,34.
eval
と LC_NUMERIC
文字列 eval はその式を標準の Perl としてパースします。 従って小数点がピリオドであることを想定します。 もしこれがカンマであるように LC_NUMERIC
が設定されると、パースは (おそらく暗黙の内に)混乱します。
use locale;
use POSIX qw(locale_h);
setlocale(LC_NUMERIC, "fr_FR") or die "Pardon";
my $a = 1.2;
print eval "$a + 1.5";
print "\n";
これは 13,5
を表示します。 これは、このロケールではカンマが小数点文字だからです。 従って eval
はこれを次のように展開します:
eval "1,2 + 1.5"
そして結果はおそらくあなたが想定したものではありません。 警告は出ません。 文字列 eval
を use locale
スコープ内で行うなら、 eval
行を以下のように変えるべきです:
print eval "no locale; $a + 1.5";
これは 2.7
を表示します。
5.004 より前のバージョンの Perl では、ほとんど ロケール情報を無視して、 たとえプログラム環境が別のものを指示していたとしても常に "C"
ロケール ("The setlocale function" を参照) が強制されているかのように 振る舞っていました。 デフォルトでは、Perl は今でもこのように動作するので、過去互換性があります。 Perl アプリケーションをロケール情報に注目するようにしたいのなら、 use locale
プラグマ("The use locale pragma" を参照)あるいは、 あまりなさそうな上京ですが単に正規表現でそうしたいなら、/l
正規表現修飾子 ("Character set modifiers" in perlre 参照) を 使わなければなりません。
5.002 から 5.003 の Perl は、使用可能である場合には LC_CTYPE
の情報を 使っていました; つまり、\w
はロケールの環境変数に従った文字を 理解していたのです。 問題は、C ライブラリがロケールをサポートしている場合には Perl がそれを 使ってしまい、ユーザーがこの機能を制御できないということでした。
5.004 より前のバージョンの Perl では、ロケール毎の照合は I18N::Collate
ライブラリモジュールを使うことで可能でした。 このモジュールは現在、やや時代遅れとなっていて、新しいアプリケーションでは 使用を避けるべきものです。 現在、LC_COLLATE
機能は Perl のコア言語に統合されました: スカラデータのロケール固有の比較は use locale
を使うことで完全に 行なわれます; このため、I18N::Collate
のスカラリファレンスを使って お手玉する必要はもはやないのです。
ロケールによる比較とソートは通常、デフォルトのソートに比べ二倍から 四倍遅くなります。 また、メモリの使用量も増大します。 Perl のスカラ変数がロケールの照合規則を使ったなんらかの文字列比較や ソートの中で現れると、それによって以前より三倍から十五倍の時間を 要するようになります(実際のところの乗数は文字列の内容、オペレーティング システム、ロケールに依存します)。 この性能ダウンは、Perl によるものよりもオペレーティングシステムの ロケールシステムの実装によるものが顕著に現れます。
Unicode CLDR プロジェクトは多くのロケールの POSIX 部分を展開します; 以下で利用可能です
http://unicode.org/Public/cldr/latest/
ここにロケール定義の大規模なコレクションがあります:
http://std.dkuug.dk/i18n/WG15-collection/locales/
これがサポート無しのものであり、どんな目的にも適合するとは 主張していないものであることに注意すべきです。 あなたの使うシステムがロケール機能のインストールを許しているのであれば、 この場所で便利な定義を見つけることができるでしょうし、あるいは自分で ロケールを定義する基礎となるようなものを見つけられるかもしれません。
"Internationalization" (国際化)はその最初と最後の文字、そしてその間にある 文字数から i18n としばしば略されます。 (なぜ(英語では) internalin ... internaliti ... i18n が省略されがちか 推測できるかも知れません。) 同様のやり方で、"localization" もしばしば l10n と省略されます。
標準 C や標準 POSIX に定義されている国際対応は、不完全で、扱いにくく、 粒度が大きすぎると酷評されます。 (ロケールは、単一のスレッドであるとか、ウィンドウグループといったものに対して 適用するのが便利であるときにもプロセス全体に適用されます)。 また、世界が等しく銀行家、バイク乗り、ゲーマーなどに分割できるのを知るとき、 標準化グループに似て、世界を国に分割しようとする傾向があります。
Unicode 対応は Perl バージョン 5.6 から始まり、バージョン 5.8 以降でより 完全に実装されました。 perluniintro を参照してください。
Perl v5.20 から、UTF-8 ロケールが Perl で対応されました; ただし LC_COLLATE
を除きます (代わりに Unicode::Collate を使ってください)。 Perl v5.16 または v5.18 を使っていてアップグレードできないなら、次のものが 使えます
use locale ':not_characters';
この形式のプラグマが使われると、ロケールの文字以外の部分、たとえば LC_NUMERIC
、のみが Perl によって使われます。 Perl は、あなたが操作する全ての文字を Unicode (実際にはプラットフォームに ネイティブな文字集合 (ASCII または EBCDIC) に加えて Unicode) に変換していると 仮定します。 ファイルのデータについては、これは以下のように指定することでも便利に行えます
use open ':locale';
このプラグマは、ファイルからの全ての入力について環境変数で指定されている ロケール ("ENVIRONMENT" 参照) から Unicode への変換と、ファイルへの 全ての出力についてそのロケールへ逆変換を行います。 (open 参照)。 ファイルハンドル単位では、どちらも CPAN から利用可能である PerlIO::locale モジュールか Encode::Locale が代わりに使えます。 後者のモジュールは ARGV
と環境変数の扱いを簡単にするメソッドも持ち、 個々の文字列で使えます。 最近多い状況として、使うロケールが UTF-8 だけであることが 分かっているなら、-C コマンドラインオプションが使えます。
この形式のプラグマは、本質的にロケールと Unicode の扱いをシームレスにします。 照合順序は Unicode の符号位置順です。 文字列の順序とソートが必要な場合は、古い形式のロケール操作よりも 多くの場合に遙かによい結果を得られる、Unicode::Collate 標準モジュールを 使うことを強く勧めます。
ここで記述されている全てのモジュールとスイッチは、 v5.20 からは単に use locale
と書くだけで使えます; 入力が UTF-8 でなく、v5.16 より前の Perl を使うか、 あるいは、v5.16 と v5.18 で :not_characters
引数なしで locale プラグマを使ったとき、 理想とは遠い振る舞いになります。 v5.20 以上で UTF-8 ロケールのみを使う場合は、この章の残りの内容は 適用されません。
マルチバイトロケールと単一バイトロケールの二つの場合があります まずマルチバイトの場合:
Perl が対応していると言える唯一のマルチバイト(ワイド文字)ロケールは UTF-8 です。 これは、実装の難しさ、高品質な UTF-8 ロケールは世界中のあらゆる 分野で使われているという事実、他のロケールと変換するために Encode モジュールを使えるというのが理由です。 従って、Big5 や Shift JIS のようなこれらのロケールの一つを使っている場合、 これらのどれか一つを行う必要があります。 UTF-8 ロケールに関しては、完全な UTF-8 ロケール対応のない (v5.20 より前の) Perl でも十分にうまく動くかもしれません (C ライブラリの実装に依存します); 単にこれらと Perl はマルチバイトになる文字を同じ方法で保管するからです。 しかし、ほとんどではなかったとしても時々、C ライブラリ実装は、LC_CTYPE
の 下では Latin-1 の範囲の上半分 (128 - 255) の文字を正しく扱えません。 ロケールの下である文字が特定の型を持っているかどうかを見るために、Perl は isalnum()
のような関数を使います。 使っている C ライブラリは UTF-8 ロケールに対してこれらの関数が動作せず、 代わりに iswalnum()
のような新しいワイド文字ライブラリ関数のみが 動作するかもしれません。 しかし、これらは単一バイトロケールのように扱われ、後述するような 制限があります。
単一バイトロケールでは、Perl は一般的にシングルバイトに合う符号位置の ロケールルールを使い、それが出来ないときは Unicode のルールを使う方針を とります (しかしこれは一様には適用されません; この節の末尾の注意を 参照してください)。 これは UTF-8 でないロケールでの多くの問題を防ぎます。 ロケールがギリシャ語の ISO8859-7 であると仮定します。 0xD7 の文字は capital Chi です。 しかし Latin1 である ISO8859-1 ロケールでは、これは乗算記号です。 POSIX 正規表現文字クラス [[:alpha:]]
はマジカルに、ギリシャ語ロケールでは 0xD7 にマッチングするけれども Latin ロケールではマッチングしません。
しかし、これを分解してみます。 \p{Alpha}
のような一部の Perl の構文は Unicode のみです。 これらは 0xD7 は常に Unicode での意味 (あるいは EBCDIC プラットフォームでの 等価物) を持つと仮定します。 Latin1 は Unicode の部分集合でであり、0xD7 は Latin1 と Unicode の両方で 乗算記号なので、ロケールに関わらず \p{Alpha}
はマッチングしません。 同じような問題は \N{...}
で起こります。 v5.20 以前では、従って生の use locale
で \p{}
や \N{}
を使うのは 悪い考えです -- ロケールが ISO8859-1 であることを 保証できないかぎり です。 代わりに POSIX 文字クラスを使ってください。
この手法のもう一つの問題は、1 バイト/複数バイトの境界をまたぐ操作は 未定義なので、許可されていません。 (この境界は符号位置 255/256 の間です。) 例えば LATIN CAPITAL LETTER Y WITH DIAERESIS (U+0178) の小文字化は LATIN SMALL LETTER Y WITH DIAERESIS (U+00FF) を返すべきです。 しかし、例えばギリシャ語ロケールでは、0xFF に文字はなく、Perl には 0xFF の 文字が実際に何を表現しているかを知る方法はありません。 従ってこの操作は許可されません。 このモードでは、U+0178 の小文字は自分自身です。
同じ問題は、(-C コマンドラインオプションか PERL_UNICODE
環境変数を 使って (perlrun を参照してください)) ISO-8859-1 でも UTF-8 でもない ロケールの標準ファイルハンドル、デフォルト open()
層、@ARGV
の 自動 UTF-8 化を有効にしている場合にも起こります。 これらは UTF-8 として読み込まれ、普通は暗黙に Unicode として 解釈されますが、ロケールの存在によって、代わりにそのロケールとして 解釈されます。 例えば、Unicode 入力での符号位置 0xD7 は、乗算記号を意味するべきですが、 ギリシャ語ロケールでは Perl はそのようには解釈しません。 全てのロケールが常に ISO-8859-1 か、不十分な C ライブラリを持っていないなら UTF-8 ロケール、のどちらかだけであることが 確実なら 問題ではありません。
もう一つの問題は、この手法は同じ文字を意味する二つの符号位置を 持つことになることです。 従ってギリシャ語ロケールでは、U+03A7 と U+00D7 はどちらも GREEK CAPITAL LETTER CHI です。
ベンダロケールはバグ持ちで悪名高く、これは Perl が制御できないコードと 相互作用するので、Perl がロケール操作コードをテストするのは困難です; 従って Perl のロケール操作コードは同様にバグ持ちかもしれません。 (しかし、Unicode が提供しているロケールはより良いはずで、問題を修正するための フィードバック機構があります。 "Freely available locale definitions" を参照してください。)
Perl v5.16 を使っているなら、(非文字部にベンダバグがない限り) locale プラグマに :not_characters
引数を使えば前述した問題はなくなります。 v5.16 がなく、動作するロケールが ある なら、それを使うことは、既に言及した コツを心に留めている限りは、ある種の特定の用途には価値があるかもしれません。 例えば、ロケール下での照合が動作するなら、 Unicode::Collate 下でのロケールよりも高速に実行されます; そしてローカルな通貨記号、月や週の名前のようなものへのアクセスを得ます。 (しかし要点を銘記するために、v5.16 では、プラグマの :not_characters
形式を 使うことでロケールの弱点なしにこれにアクセスできます。)
注意、1 バイトに収まる符号位置に対してロケールの規則を使うポリシーと、 収まらないものに対する Unicode の規則を使うポリシーについては、一律には 適用されません。 v5.12 より前では、これは場当たり的でした; v5.12 では、大かっこ文字クラス以外の 正規表現マッチングではかなり一貫して適用されました; v5.14 では全ての 正規表現マッチングに拡大されました; v5.16 では "\L"
や uc()
のような 大文字小文字操作に拡大されました。 照合については、全てのリリースについて、システムの strxfrm()
関数が 呼び出され、その結果が結果となります。
幾つかのオペレーティングシステムにおける環境でのロケールサポートは、 おかしなもので、Perl がそれに対処したり使ったりできないようなものです。 そういった不完全なものは、use locale
が有効になったときに Perl を 不可思議なハングアップに導いたり、コアダンプをさせたりします。 このようなシステムに直面した場合、詳しい状況を <perlbug@perl.org> に レポートし、そして使用しているシステムのベンダーに連絡してください: 問題の幾つかに対するバグフィックスがされているかもしれません。 そういったバグ修正は、オペレーティングシステムのアップグレードと 呼ばれることがあります。 Perl のソースがあるなら、前述の "Testing for broken locales" で 記述されているテストの出力を perlbug のメールに含めてください。
I18N::Langinfo, perluniintro, perlunicode, open, "isalnum" in POSIX, "isalpha" in POSIX, "isdigit" in POSIX, "isgraph" in POSIX, "islower" in POSIX, "isprint" in POSIX, "ispunct" in POSIX, "isspace" in POSIX, "isupper" in POSIX, "isxdigit" in POSIX, "localeconv" in POSIX, "setlocale" in POSIX, "strcoll" in POSIX, "strftime" in POSIX, "strtod" in POSIX, "strxfrm" in POSIX.
Perl が C プログラムに組み込まれているときに特に考慮することについては "Using embedded Perl with POSIX locales" in perlembed を参照してください。
Jarkko Hietaniemi の原文書 perli18n.pod は perl5-porters の助けの元、 Dominic Dunlop によって大きく変更されました。 表現に関しては Tom Christiansen が少し作業をし、Perl 5 porters によって 更新されました。