追記・文字コード
いまいちわかりにくいかなと思ったのでもうちょっと解説。
対象はMacのTerminalを想定。
Terminal.appはウィンドウ設定を開いてプルダウンをディスプレイに変更すると、「文字セットエンコーディング」という設定項目があり、「Unicode(UTF-8)」に設定されている。その為、スクリプトの出力をTerminal上で確認したい場合は、UTF-8で出力しないと文字化けしてしまう。
なお、MacPortsなどを使用してnkfをインストールすれば、スクリプトの出力をパイプすることでUTF-8に変換することも可能だ。
perl xxx.pl | nkf -w
MacPortsに関してはこちらのPorticusを使えばGUIが付いてくるので使いやすい。MacPortsでインストールされるコマンドへのパスが通ってない場合は、ログインシェルに設定が必要だ。
http://www.moongift.jp/2007/07/porticus/
とりあえず、Perlの出力をUTF-8で行えば良いとして、その他Terminalでperlを使うときの方針
- 読み込んだデータはUTF-8に変換してしまう。utf8フラグをオンにして処理を行い、出力時にはフラグを落す。
- スクリプトの文字コードもUTF-8で保存する。「use utf8」しておく
- 改行コードはLF
1つめのUTF-8への変換は、Encodeモジュールを使う(他にも方法があるがここでは紹介しない)。Encodeモジュールを使うとutfフラグがオンになる。utf8フラグがオンになっている文字列とそうでない文字列は混ぜるなキケンである。したがって、スクリプト中に「use utf8」をしておき、スクリプトもUTF-8で保存する。こうすることで、スクリプト中の文字列リテラルがutf8フラグがオンになった文字列として処理され、連結したり、長さを取得したりしても問題なくなるというわけ。
use strict; use warnings; use utf8; use Encode; use constant INPUT_ENCODING=>'shiftjis'; use constant OUTPUT_ENCODING=>'utf8'; my $input_enc = Encode::find_encoding(INPUT_ENCODING); my $output_enc = Encode::find_encoding(OUTPUT_ENCODING); # 第一引数に与えられた文字列をutf8フラグ付きUTF-8にする sub inputFilter{$input_enc->decode($_[0])} # 第一引数に与えられた文字列をutf8フラグなしUTF-8にする sub outputFilter{$output_enc->encode($_[0])} # ファイルを1行毎に処理する関数。なおCSVを処理する場合はText::CSVを使用すると良い # inputFilterを使っているので、この関数はshiftjisのファイルに対してしか使えない。 sub file_foreach{ my $filename = shift; my $func = shift || sub{$_[0]}; # 関数リファレンスを受けとる。なければ第一引数を返すだけの関数 open my $fh,$filename or die $!; flock $fh,1; while(my $r = <$fh>){ $r = inputFilter($r); chomp $r; $func->($r); } close $fh; }
データを出力する場合
my $fname = $ARGV[0]; file_foreach($fname,sub{ my $line = shift; # 文字列を直接混ぜても大丈夫 print outputFilter("[入力行:$line]\n"); });
配列に保持する場合
my $fname = $ARGV[0]; my @data; my $filter = sub{"☆$_[0]☆"}; file_foreach($fname,sub{ my $line = shift; # フィルタをかけてみたり push @data,$filter->($line); }); ## テストとして出力。 foreach(@data){ print outputFilter("$_\n"); }