文字コード候補の指定

Encode::Guess を使う時に一点だけ配慮しなければならない点があります。それは、use する時に可能性のある文字コードを Perl のエンコーディング表現で指定しなければならない点です。以下のコードがこの部分に相当します。
use Encode::Guess qw/cp932 euc-jp 7bit-jis utf8/;
ここでは、日本語の主な文字コード4つを指定しています。この指定は通常の文字コード表記と異なり、「UTF-8」の場合は「utf8」と小文字のハイフンなしになるので注意して下さい(※4)。

※4 実は表記の間違いや揺れをある程度モジュール側で解釈してくれますが、プログラムコードが混乱するので正式な表記をするように心がけて下さい。

何が指定できるかは、以下のコマンドで表示できます。

perl -MEncode -e 'print join qq{
}, Encode->encodings(q{:all}),qq{
}'

日本語関係のエンコーディング表現の詳細は、以下のコマンドで表示できます。
perldoc Encode::JP

文字コード自動判別の汎用関数

さてそれでは、この文字コード判別フローを転用して、汎用的なファイルオープン関数を書くと例えば以下のようになります。

use strict;
use warnings;
use utf8;
use Encode::Guess qw/cp932 euc-jp 7bit-jis utf8/; #文字コードの候補を指定して use する

# 文字コードを判別してファイルオープン(読み込み用)
# 引数:ファイルパス
# 戻り値:オープンしたファイルハンドル(エラーの場合は未定義)、エラーメッセージ
sub open_binary4read{
	my $file = shift;
	
	#引数チェック
	$file and -f $file
		or return (undef, 'File path not set or file does not exists.');
	
	my $fh;
	unless (open ($fh, '<:raw', $file)){ #文字コード指定なしで1回ファイルを開く
		return(undef, "OPEN FAILED: $file, $!");
	}
	my ($temp, $i);
	while ($temp .= <$fh> and ++$i < 50){ #最大50行(実は49行)まで変数に保存
		eof and last;
	}
	close ($fh);
	my $genc = guess_encoding($temp); #文字コード判別
	
	#Perlでのエンコーディング指定を取得。判別できない場合のデフォルトを指定
	my $enc = eval{$genc->name} || 'cp932';
	
	#もう一度ファイルを開く
	unless (open ($fh, "<:encoding($enc)", $file)){
		return(undef, "OPEN FAILED: $file, $!");
	}
	
	#取得したファイルハンドルを返す
	return ($fh, undef);
}

#__END__

#テスト

binmode STDOUT, ':utf8'; # Windows の場合は cp932

#読み込み
my ($fh, $error) = &open_binary4read(shift);

#ファイルハンドルを使うテスト:内容を書き出してみる
if ($fh and !$error){
	while(<$fh>){
		print $_;
	}
	
	close ($fh);
}
関数の下にテスト用のコードも入れましたので、コードを open_binary.pl の名前で保存すると以下のコマンドでファイルが文字化けせずに読み込めているかを確かめる事ができます。

perl open_binary.pl (ファイル名)



■All Aboutで「お金」について、アンケートを実施中です!
回答いただいた内容をAll About記事企画の参考にさせていただきます
※2021/7/1~2021/7/31まで

・【誰でも回答可】「毎月の家計についてのアンケート」に回答する
抽選で10名にAmazonギフト券1000円分プレゼント

※記事内容は執筆時点のものです。最新の内容をご確認ください。
※OSやアプリ、ソフトのバージョンによっては画面表示、操作方法が異なる可能性があります。