2016-08-04 2 views
1

잘못된 UTF-8이 포함 된 파일 (유효한 UTF-8이 포함되어 있음)을 읽을 때 경고 메시지를 인쇄하려고합니다. 그러나 유효하지 않은 데이터가 파일 끝에 있으면 경고를 출력 할 수 없습니다. 다음 MVCE는 무효 UTF-8 데이터를 포함하는 파일을 생성한다 (파일의 생성을 일반적인 질문이 단지 MVCE을 생성하기 위해 여기 첨가 관련이없는)파일 끝에 잘못된 형식의 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"; 
} 

출력은 :

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");을 사용할 수 있습니다 (유닉스 텍스트 파일은 항상 줄 바꿈으로 끝나야 함).

+0

그래서 먼저 파일을 바이트로 읽은 다음'Encode :: decode ('utf-8', $ raw, Encode :: FB_QUIET)'문자열을 단계적으로 읽습니다. 각 실패시 데이터의 나머지 부분과 반복합니다. 최후의 수단으로 예,하지만 나는 오히려 경고를 출력하기 위해 자신의 디코딩 알고리즘을 고안하는 것을 피하고 싶습니다. 아마도 대신 ['Encode'] (https://metacpan.org/pod/Encode)에 대한 버그 보고서를 제출해야합니까? –

2

본질적으로 당신이보고있는 것은 perlIO 시스템이 utf-8 시퀀스의 중간에 끝나는 블록 읽기를 처리하려고 시도한다는 것입니다. 원시 바이트 버퍼에는 여전히 잘못된 바이트가 있습니다. 그러나 인코딩 된 버퍼에는 아직 제대로 디코딩되지 않으며 나중에 다른 문자를 찾으려고하기 때문에 해당 내용이 없습니다. 인코딩 레이어를 팝핑하고 다른 읽기를 수행하고 길이를 확인하여이를 확인할 수 있습니다. 원시 또는 bin 파일 모드의 $의 FH를 수행

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

잘 모르겠어요, 당신은 당신의 개방 인코딩 시작을 할 수 있습니다 '원시'대신에, 나는 이후 층에 자신을 많은 관심을 지불 한 적이 보통 그냥 작동합니다. 이 코드 블록이 테스트 케이스에서 작동한다는 것을 알고 있습니다 :)

관련 문제