Perl の use locale を Windows 環境で使用するときの注意

http://d.hatena.ne.jp/jishiha/20040309#p3 で書いた use locale の問題が解決した。id:amatubu さんが情報を提供してくれた。大感謝です。この問題に関してネット上を検索してまわったが解決方法はどこにも見あたらなかった。同じような問題に直面した人が今度はここで情報が得られるようメモしておく。

問題は use locale と宣言して、EUC-JP のデータを sort しようとすると Perl がハングしてしまうというもの。

use locale と宣言したとき、デフォルトのロケールが採用されるのだが、Windows のデフォルトロケールは Japanese_Japan.932(=Shift_JIS)なので、sort する EUC-JP データと異なる。このため、不具合が生じるようだ。

use locale;

@text = ('Apple','Big','apple','big','あ','一');
print join(',', sort @text), "\n";

このスクリプトを普通に、つまり Shift_JIS で保存し Windows 上で実行すれば何の問題はないのだが、EUC-JP で保存した後実行すれば、ハングする問題が再現できるはずだ。

これを防ぐには、EUC-JP をサポートするロケールを明示的に宣言すればいい。ロケールの宣言は、

use POSIX qw(locale_h);setlocale(LC_COLLATE,"ロケール名");

とやればいいと id:amatubu さんに教わる。あとは EUC-JP をサポートする Windowsロケール名を見つければいい。Japanese_Japan.932 の 932 を入れ替えればいいと当たりをつけ、Windows の Control Panel > Regional and Language Options > Advanced > Code page conversion tables(僕の持っているのは英語版 WinXP です。日本語に適当に読み替えてください。) を探した結果、Japanese_Japan.20932 だとわかった。

use locale;
use POSIX qw(locale_h);setlocale(LC_COLLATE,"Japanese_Japan.20932");

@text = ('Apple','Big','apple','big','あ','一');
print join(',', sort @text), "\n";

これを EUC-JP で保存し実行してもハングしない。もちろん日本語の文字は EUC-JP なのでそのままではちゃんと表示されないが、アルファベットはきちんと、apple,Apple,big,Big の並び順で並び、no locale と宣言するよりも良い。

日本語モードかどうかで分岐させるには、

use locale;

$JapaneseMode = 'yes'; #yes or no

if $JapaneseMode eq 'yes' {
    use POSIX qw(locale_h);setlocale(LC_COLLATE,"Japanese_Japan.20932");
}

@text = ('Apple','Big','apple','big','あ','一');
print join(',', sort @text), "\n";

とすればよい。