perlでUTF-16LE + BOM
稀に、ファイルをUTF-16LE + BOMで保存したいということがある。
そもそもBOMが付いている訳だから、エンディアンがどうであるかを気にする必然は無いと思うし、特定のエンディアンしか読めないのならUTF-16LEと言い切ってしまえば良い訳で、その場合BOMは無用の長物だ。とはいえ、そういうことがしたい場合もあるにはある。(Winとかそっち方面で…しくしく。)
今日は「そういう事がしたい場合」だった。そこでperlで変換スクリプトを書こうと思ったのだが、UTF-16LE + BOMってどう変換するのかがいまいち不明だ。そういうエンコードの指定がある訳ではなさそうだし。ということで、普通にUTF-16LEでencodeしてからBOMを付けることにした。
#!/usr/bin/perl use strict; use warnings; use Encode; use Encode::Guess; use Getopt::Std; my $opts = {}; getopt( 'I', $opts ); my $buffer = join '', <>; my $enc = $opts->{I} ? $opts->{I} : do { my $e = guess_encoding( $buffer ); ref $e ? $e : 'utf-8'; }; print pack('H*','fffe'), encode( 'utf-16-le', decode( $enc, $buffer ) ); exit;
BOM = Byte Order Markはファイル冒頭、最初の文字より前に入る特殊文字でFEFFが割り当てられているが、これがエンディアンによってFFFEになる(表現される)ことを利用して、エンディアンがどちらかを見分ける。
ということで、LEの場合は逆転させてfffeを頭に付けてあげればOKなはず。スクリプトではファイル内容を読んでEncode::Guessで推測すると言った処理もしている。(doとかちょっと気持ち悪いが…。)ただしこのコードだと最初にファイルを全部メモリ上に置くことになるので、大きいファイルを扱う場合はもう一工夫必要そう。
で結局のところ、正解はどんなんだろう。