Perl 5.6 以降の Unicode 周りの話は華麗にスルーしてきたんだけど、あらためて昔のスクリプトをどうにかしようと思い、久々に Perl を触って悪戦苦闘。まずデータ構造の扱いにくさに泣きそうになる。ついで日本語。なんか Unicode がどうのこうでやたらといろんな方法がある。無理。こういうとき Perl の TMTOWTDI は本当に腹立たしい。どのやり方でもエレガントにできない言い訳じゃないのかと。
とりあえず設定を全部 YAML に逃がして、最終的に Perl でないもので動くように(!)持って行きたいがための作業なので、面倒なところはやはりスルーしつついくのがベストのような気がして来た。幸いこれ、日本語を直接読み書きしなきゃいけないものじゃないしな。
例によって嘘、大げさ、紛らわしい場合はツッコミぷりーず。
基本
- 5.8 以降では Perl は内部的に文字列を UTF-8 で扱うものとする
- Perl 的に認められた文字列には UTF-8 フラグがつく
- UTF-8 フラグのついていないものでも人間が文字列として認識するのは自由
use utf8;
コードが UTF-8 で書かれていることを宣言する。もしかすっと将来的にはこれがデフォルトになるのかも。
マルチバイト文字列を正しくマルチバイト文字列として扱おうとしてくれるが、副作用としてマルチバイト文字を print したときに警告が出るようになる。
逆につけなくても今まで通り日本語をコード中に書くことはできる1。これをそのまま print することは可能。euc-jp だろうが utf-8 だろうが同じ手法が使える。もちろん Shift JIS のように地雷を踏みやすいエンコーディングを選ぶ際は自己責任で。ファイルの読み書きも従来通りに動かせます2。
ただし、use utf83しておかないと、シリアライズ系のものが軒並み \xXX 形式になってしまい、コマンドラインでの作業効率はよろしくない。つけてもつけなくても同じ結果になるモジュールもあるが、最近の UTF-8 フラグを解釈してくれるモジュールを扱う場合はつけておいた方が少し幸せになれるかも4。
use utf8 しておくことで他にも嬉しいケースはあるかもしれないんだけど、あんまり詳しく調べてません。正規表現マッチを日本語で書けるような気がする。
binmode STDOUT => ":utf8";
UTF-8 フラグのついたマルチバイト文字列を print するときに UTF-8 フラグを落としてくれるので、警告が出なくなる。use utf8 したときはこれ書いておかないとコマンドラインでの作業が邪魔くさくなる。
もちろん一つ一つ
Encode::encode()
して出すっつー酔狂な選択をしてもいいけど、そんなの面倒じゃん。
use encoding CHARSET;
Perl 5.8 で内部的には UTF-8 でイクっつーのは決まったんだけど、そんでもどうしてもコードを Shift JIS で書きたいやい、UTF-8 なんてやだいやだいという場合にしゃあなしで使うことを許されるもの。
use encoding "euc-jp";
って書いたら euc-jp で書いてあるコードでも UTF-8 で書かれているのと同じようにマルチバイトな文字列として扱ってくれて、なおかつ STDIN も STDOUT も euc-jp を期待して動いてくれる。
当然、UTF-8 フラグ周りの警告も出ない。use utf8; とは排他と考えるべし。(実際には使えるみたいだけど、「混ぜるな危険」が基本です。)
use open
スクリプトもデータも euc-jp なんだけど、もうターミナルは UTF-8 で統一したいし、他の UTF-8 前提で動いてるアプリと組み合わせたい、という場合は、コード中にマルチバイトなリテラルを書いてなければ、
use open IN => ":euc-jp";
use open OUT => ":utf8";
binmode STDOUT => ":utf8";
とすることでそれなりに対処できる。上の例では euc-jp の入力、UTF-8 な出力を期待して動く。
ターミナルだけの問題なら screen でも対応可能だけど、他のアプリと繋げたいという場合は open を使うと楽できると思う。
use Encode;
使ってないんでよく分からないけど、これは変換以外に気にするポイントはないのかな。
なんかねぇ、似たような単語でいろいろな機能が動くんで、ものすごく分かりにくいです。