2016-08-04 4 views
1

無効なUTF-8が含まれているファイル(有効なUTF-8が含まれているはずです)を読むときに警告メッセージを表示しようとしています。ただし、無効なデータがファイルの最後にある場合は、警告を出力できません。出力されたファイルの最後に不正な形式のUTF-8を検出する方法はありますか?

use feature qw(say); 
use strict; 
use warnings; 

binmode STDOUT, ':utf8'; 
binmode STDERR, ':utf8'; 

my $bytes = "\x{61}\x{E5}\x{61}"; # 3 bytes in iso 8859-1: aåa 
test_read_invalid($bytes); 
$bytes = "\x{61}\x{E5}"; # 2 bytes in iso 8859-1: aå 
test_read_invalid($bytes); 

sub test_read_invalid { 
    my ($bytes) = @_; 
    say "Running test case.."; 
    my $fn = 'test.txt'; 
    open (my $fh, '>:raw', $fn) or die "Could not open file '$fn': $!"; 
    print $fh $bytes; 
    close $fh; 
    my $str = ''; 
    open ($fh, "<:encoding(utf-8)", $fn) or die "Could not open file '$fn': $!"; 
    $str = do { local $/; <$fh> }; 
    close $fh; 
    say "Read string: '$str'\n"; 
} 

MVCEは無効とUTF-8のデータを含むファイルを(ファイルの作成は一般的な質問には関係ありません、それは単にMVCEを生成するためにここに追加されました)を作成します
Running test case.. 
utf8 "\xE5" does not map to Unicode at ./p.pl line 22. 
Read string: 'a\xE5a' 

Running test case.. 
Read string: 'a' 

最後のテストケースでは、ファイルの末尾の無効なバイトが、PerlIOレイヤー:encoding(utf-8)によって黙って無視されるようです。

答えて

0
open (my $fh, '>:raw', $fn) or die "Could not open file '$fn': $!"; 
#the end of the file need a single space to find a invalid UTF-8 characters. 
print $fh "$bytes "; 

出力:

Running test case.. 
utf8 "\xE5" does not map to Unicode at ent.pl line 23. 
Read string: 'a\xE5a ' 

Running test case.. 
utf8 "\xE5" does not map to Unicode at ent.pl line 23. 
Read string: 'a\xE5a ' 
+0

ファイルを書くコードの部分は私が説明しようとしている一般的な問題の一部ではありません。 [MCVE](http://stackoverflow.com/help/mcve)を作成するように追加されました。ファイル自体を変更したり、同じファイル名に書き換えることはできません。 –

1

私はあなたが求めているのかわからないんだけど。文字列のエンコーディングエラーを検出するには、単に文字列のデコードを試みます。ファイルへの書き込みからエラーが発生した場合は、closeがエラーを返します。あるいはchomp($_); print($fh "$_\n");を使用できます(UNIXテキストファイルは常に改行で終了する必要があります)。

+0

まず、ファイルをバイトとして読み込み、 'Encode :: decode( 'utf-8'、$ raw、Encode :: FB_QUIET)'という文字列としてステップインします。各失敗時に、データの残りの部分が繰り返されます。最後の手段として、私はむしろ警告を出力するために自分のデコードアルゴリズムを工夫することを避けたいと思っています。おそらく私は代わりに['Encode'](https://metacpan.org/pod/Encode)に対するバグレポートを提出するべきでしょうか? –

2

あなたが見ているのは、utf-8シーケンスの途中で終了するブロック読み出しを処理しようとするperlIOシステムです。生のバイトバッファにはまだ無効なバイトがありますが、エンコードされたバッファはまだ正しくデコードされず、後で別の文字を見つけることを望んでいるため、その内容はまだありません。これを確認するには、エンコーディングレイヤをポップして別の読み込みを行い、長さをチェックします。

binmode $fh, ':pop'; 
my $remainder = do { local $/; <$fh>}; 
die "Unread Characters" if length $remainder; 

私はあなたとあなたのオープンエンコードの開始を持っているしたい場合があり、わからない:、生またはbinmodeをする$ FHを行う「:生」の代わりに、私はそれ以来、レイヤーに自分自身を多くの注意を払ったことがありません通常は動作します。私はこのコードブロックがあなたのテストケースのために働くことを知っています:)

関連する問題