以前もやったけど実はよくわかってなかった。
ので再度まとめなおし。
日本語 Windows 上では ShiftJIS のファイルが一般的なわけで。
何も考えずに Perl スクリプトを書くと ShiftJIS で作成されてしまう。
こうすると何が問題かというと、
$a = "ミソ";
のように 2 バイトコードを使った場合にコンパイルエラーになってしまう。
(シングルクォートで回避できる文字もあるけど、これは本質的ではない。
詳しくは
Shift-JISテキストを正しく扱う を参照)
で、回避する方法としては
(1) use encoding "sjis"; とやってスクリプトの文字コードを明示的に指定
(2) スクリプトを UTF-8 で保存する
の 2 つがある。少なくとも。
どちらの方法を取るにしても、デフォルトの文字コードが変わるので、外部の文字コードが異なっていると問題が発生する。
今までは後者の方法を使って、外部のファイルとやりとりする場合は
open(IN, "<:encoding(sjis)", "$filename");
open(OUT, ">:encoding(sjis)", "$filename");
のように解決していた。
今回問題になったのは、標準出力と system() 関数。
system("echo ミソ");
のようにすると、コマンドプロンプトで文字化けしてしまう。
標準出力は (1) の方法だとうまくいくらしいけど、system() はどちらの方法でもダメらしい。
とりあえず
Perl 5.8 Documentation - perljp - 日本語 Perl ガイド
Perl-5.8 MEMO
Perl 5.8.x Unicode関連
とかを参考に色々試したところ、(2) の方法をベースに
use Encode;
$msg = "ミソ";
Encode::from_to($msg, 'utf8', 'sjis');
print "echo $msg";
とやれば期待通りの動作をすることが判明。
(ちなみに use encoding "sjis"; がソースのどこかに残っているとうまくいかない。
グローバルってそういうことか・・・。)
これでうまくいくと思いきや。
open(IN, "<:encoding(sjis)", "$filename");
として読み込んだファイルに対して正規表現の検索がうまくいかない。
また、このままでは上記の Encode::from_to($msg, 'utf8', 'sjis'); みたいのもうまく通らないようで、
utf8::encode($line);
が必要らしい。
あと、こうすると文字コードの境界がうまく処理できない?らしいので
$line =~ m#.*([^/]+)$#
のように欲張りマッチではなく
$line =~ m#.*?([^/]+)$#
のように非欲張りマッチを使う必要があったりもした。
で、さらに。
utf8::encode($line); とかやってしまうと
open(OUT, ">:encoding(sjis)", "$filename") のようにして出力できなくなってしまう。
この場合は open(OUT, ">", "$filelist") と普通にオープンして
Encode::from_to($line, 'utf8', 'sjis') したあとで書き出せば OK。
・・・どう考えてももっと簡単に処理できる気がする。
今後も似たような問題発生しまくるだろうし、少しずつでも知識を確実なものにしないと。
おまけ。クリップボードの使い方。
use Win32::Clipboard;
Win32::Clipboard()->Set($buf);
↓みたいに one liner で使うと便利かも。
perl -MWin32::Clipboard -e "Win32::Clipboard()->Set('a' x 17000)"