Windows環境のActivePerlのencodingモジュールと改行の関係
Windowsの改行コードは"\x0d\x0a"
、Unixでは"\x0a"
などと異なりますが、Perlでは同じスクリプトを複数の環境でも動かせるように、改行コードを"\n"
で扱うことができるようになっています。
実際のWindows版ActivePerlでは以下のような変換を行っています。
- 標準入力で
"\x0d\x0a"
は"\x0a"
に変換される - 標準出力で
"\n"
は(最終的に)"\x0d\x0a"
に変換される - 標準エラーで
"\n"
は(最終的に)"\x0d\x0a"
に変換される
> echo A| perl -ne "printf(qq{%v02X\n}, $_)" 41.0A > perl -e "print qq{A\n}" | hexdump 00000000: 41 0D 0A - |A | 00000003; > perl -e "die qq{A\n}" 2>&1 | hexdump 00000000: 41 0D 0A - |A | 00000003;
(hexdumpはgnuwin32に含まれる物を使っています。)
しかし、encodingモジュールを使うと標準入力と標準出力のエンコーディングが影響を受け、標準入力と標準出力の改行の変換が働かなくなります(仕様かどうかは分かりません)。
- 標準入力で
"\x0d\x0a"
はそのまま読み込まれる - 標準出力で
"\n"
は"\x0a"
に変換される - 標準エラーはencodingモジュールに関係しないので影響を受けない
> echo A| perl -Mencoding="cp932" -ne "printf(qq{%v02X\n}, $_)" 41.0D.0A > perl -Mencoding="cp932" -e "print qq{A\n}" | hexdump 00000000: 41 0A - |A | 00000002; > perl -Mencoding="cp932" -e "die qq{A\n}" 2>&1 | hexdump 00000000: 41 0D 0A - |A | 00000003;
改行の変換が働かなくなるのを防ぐにはbinmodeで改行コードを再設定するか、encodingモジュールでの標準入力と標準出力の設定を無効にすることです。無効化した場合は、他のモジュールで設定します。
> echo A| perl -Mencoding="cp932" -ne "BEGIN{ binmode STDIN => ':crlf' } printf(qq{%v02X\n}, $_)" 41.0A > perl -Mencoding="cp932" -e "BEGIN{ binmode STDOUT => ':crlf' } print qq{A\n}" | hexdump 00000000: 41 0D 0A - |A | 00000003;
スクリプトで書くと次のようになります。binmodeで設定しています。
use strict; use warnings; use encoding "cp932"; binmode STDIN => ':crlf'; binmode STDOUT => ':crlf'; binmode STDERR => ':encoding(cp932)'; ...
encodingモジュールでの標準入力と標準出力の設定を無効化した場合は、他のモジュールで設定します。ここではopenプラグマを使ってファイルも同時に設定しています。
use strict; use warnings; use encoding "cp932", STDIN => undef, STDOUT => undef; use open qw(:encoding(cp932) :std); ...
小飼弾氏のよれば、encodingモジュールはあくまでも古いスクリプトを救済するためのモジュールとのことなので、新規に書き下ろす場合はUTF8で書いて、utf8モジュールを使いましょうとのことです。