處理無效的 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'