处理无效的 UTF-8
读无效的 UTF-8
在读取 UTF-8 编码数据时,重要的是要注意 UTF-8 编码数据可能无效或格式错误。这些数据通常不应被你的程序接受(除非你知道自己在做什么)。当意外遇到格式错误的数据时,可以考虑不同的操作:
- 打印堆栈跟踪或错误消息,并正常中止程序,或
- 在出现格式错误的字节序列的位置插入替换字符,向 STDERR 输出警告消息并继续读取,因为没有发生任何事情。
默认情况下,Perl 会告诉你关于编码故障的信息,但它不会中止你的程序。你可以通过使 UTF-8 警告致命来使你的程序中止,但要注意致命警告中的警告 。
以下示例将编码 ISO 8859-1 中的 3 个字节写入磁盘。然后它尝试再次读取字节作为 UTF-8 编码数据。其中一个字节 0xE5
是无效的 UTF-8 单字节序列:
use strict;
use warnings;
use warnings FATAL => 'utf8';
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
my $bytes = "\x{61}\x{E5}\x{61}"; # 3 bytes in iso 8859-1: aåa
my $fn = 'test.txt';
open ( my $fh, '>:raw', $fn ) or die "Could not open file '$fn': $!";
print $fh $bytes;
close $fh;
open ( $fh, "<:encoding(utf-8)", $fn ) or die "Could not open file '$fn': $!";
my $str = do { local $/; <$fh> };
close $fh;
print "Read string: '$str'\n";
该程序将以致命的警告中止:
utf8 "\xE5" does not map to Unicode at ./test.pl line 10.
第 10 行是第二行,当尝试从文件中读取一行时,错误发生在 <$fh>
行的部分。
如果你没有在上述程序中发出致命警告,Perl 仍会打印警告。但是,在这种情况下,它会尝试通过将四个字符\xE5
插入流中来从错误字节 0xE5
中恢复,然后继续下一个字节。结果,该程序将打印:
Read string: 'a\xE5a'