【发布时间】:2018-12-14 23:28:14
【问题描述】:
我有时不得不从外部源读取文本文件,这些文件可以使用各种字符编码;通常是 UTF-8、Latin-1 或 Windows CP-1252。
有没有办法方便地读取这些文件,像 Vim 等编辑器那样自动检测编码?
我希望有一些简单的东西:
open(my $f, '<:encoding(autodetect)', 'foo.txt') or die 'Oops: $!';
请注意,Encode::Guess 不能解决问题:它仅在可以明确检测到编码时才有效,否则它会发出嘶哑的声音。大多数 UTF-8 数据名义上是有效的 latin-1 数据,因此它在 UTF-8 文件上失败。
例子:
#!/usr/bin/env perl
use 5.020;
use warnings;
use Encode;
use Encode::Guess qw(utf-8 cp1252);
binmode STDOUT => 'utf8';
my $utf8 = "H\x{C3}\x{A9}llo, W\x{C3}\x{B8}rld!"; # "Héllo, Wørld!" in UTF-8
my $latin = "H\x{E9}llo, W\x{F8}rld!"; # "Héllo, Wørld!" in CP-1252
# Version 1
my $enc1 = Encode::Guess->guess($latin);
if (ref($enc1)) {
say $enc1->name, ': ', $enc1->decode($latin);
}
else {
say "Oops: $enc1";
}
my $enc2 = Encode::Guess->guess($utf8);
if (ref($enc2)) {
say $enc2->name, ': ', $enc2->decode($utf8);
}
else {
say "Oops: $enc2";
}
# Version 2
say decode("Guess", $latin);
say decode("Guess", $utf8);
输出:
cp1252: Héllo, Wørld!
Oops: utf-8-strict or utf8 or cp1252
Héllo, Wørld!
cp1252 or utf-8-strict or utf8 at ./guesstest line 32.
Borodin 答案中“更新”下的版本仅适用于 UTF-8 数据,但适用于 Latin-1 数据。
如果您需要同时处理 UTF-8 和 Latin-1 文件,则不能使用 Encode::Guess。
这与this one 不是同一个问题:我正在寻找一种在打开文件时自动检测的方法。
【问题讨论】:
-
没有办法可靠地检测纯文本的字符集。
-
不是 100% 可靠,不。但肯定可以对主要字符集进行“足够好”的检测。即使有 1% 的失败率,它仍然比仅仅假设 UTF-8 或 Latin-1 并且一直跌倒或显示奇怪的字符要好。 (例如,vim 做得很好:我不记得是否曾经误检测过文件。)
-
请注意,Windows 1252 (CP-1252) 不与 ISO-8859-1 相同。前者在高位寄存器
"\x80"到"\9F"的前16 个字符中具有可打印字符,后者具有相同的未分配范围,以便为C1 控制字符集留出空间。 -
Windows-1252 (cp1252) 是 iso-8859-1 的超集。 (例如,HTML5 使用 windows-1252 作为默认值来处理错误指定的 Windows 内容。)
-
@mscha:我评论只是因为您在原始帖子中写了
latin-1/windows-1252。 Latin-1 和 ISO-8859-1 是相同编码的两个名称,但 CP-1252 不同。在猜测编码时,最好假设,如果样本数据使用字符代码"\x80"到"\9F",那么它使用的是可打印字符的 CP-1252。在 Latin-1 中,Latin-1 Supplement 将控制字符分配给该范围,但我从未见过它们被使用过,而且我认为现有的 32 个 ASCII 控制字符足以满足任何目的。
标签: perl io character-encoding