我有一个perl存储文件,(当带有dumper的dumper时)其中包含以下字符串:
my $str1 = "1 = educa\x{c3}\x{a7}\x{c3}\x{a3}o";
my $str2 = "2 = educa\x{e7}\x{e3}o";
我一直在尝试制定合理的策略,以输出UTF8(另请参见perl Encode::Guess with and without hints - detecting utf8)。
让我继续上面的perl代码,并获取一些声明:
use 5.18.2;
use Encode qw( encode_utf8 decode_utf8 from_to encode decode);
use Encode::Guess;
use Encoding::FixLatin qw(fix_latin);
sub sayStrings() {
say fixEnc($_[0]);
say fixEnc($_[1],'hint');
say "";
};
sub fixEnc() {
my $data = $_[0];
my $enc = "";
if ($_[1]) {
$enc = guess_encoding($data, qw/utf8 latin-1/);
} else {
$enc = guess_encoding($data);
};
if (!ref($enc)) {
return "ERROR: Can't guess: $enc for $data";
} else {
my $flag1a = utf8::is_utf8($data);
my $flag2a = utf8::valid($data);
$data .= "; encoding: ".$enc->name.", is_utf8=$flag1a, valid=$flag2a";
return $data;
};
};
现在开始提问!我将使用各种摘要来补充该代码。
say "Question 1";
&sayStrings($str1, $str2);
和
use open IO => ':encoding(UTF-8)';
say "raw";
&sayStrings($str1, $str2);
都给:
Question 1
1 = educação; encoding: utf8, is_utf8=, valid=1
2 = educa??o; encoding: iso-8859-1, is_utf8=, valid=1
问题1A:use open IO => ':encoding(UTF-8)';
什么都不做?我猜我的系统已经设置为UTF8。是吗?
问题1B:为什么2中的字符不能正确显示?可以正确检测到编码,但是当字符串以UTF输出时,'çã'成为系统不知道(或不存在)的UTF字符了吗?
现在是问题2:
use open IO => ':encoding(UTF-8)',':std';
say "Question 2";
&sayStrings($str1, $str2);
给予:
Question 2
1 = educação; encoding: utf8, is_utf8=, valid=1
2 = educação; encoding: iso-8859-1, is_utf8=, valid=1
问题2:为什么这样做会使latin-1字符串正确显示,却破坏了UTF8字符串? (即,似乎通过添加:std,将str1中的字符序列解释为latin-1,而不是UFT8,请参见perl Encode::Guess with and without hints - detecting utf8)。为什么会这样?
问题3:
use open IO => ':encoding(UTF-8)',':std';
say "fix_latin";
&sayStrings(&fix_latin($str1), &fix_latin($str2));
给予
fix_latin
1 = educação; encoding: utf8, is_utf8=1, valid=1
2 = educação; encoding: utf8, is_utf8=1, valid=1
问题3:我猜fix_latin指示字符串为utf8,因此字符串可以正确打印。因此,对于将字符串符号发布为utf8和binmode显然有一些我不了解的地方。什么事?
非常感谢!
(P.S。已尝试阅读有关此文档的文档,但是的,请发送链接以解释此问题-理想情况下,以清晰的语言提供大量示例...)
答案 0 :(得分:2)
首先,您必须认识到$str2
可以看作是使用iso-8859-1编码的字符串,而且它也是Unicode Code Points的字符串。这是因为使用iso-8859-1编码的字符串与Unicode代码点的字符串没有区别。例如,decode('iso-8859-1', $str)
产生$str
。这意味着,向期望使用Unicode代码点的字符串的人提供使用iso-8859-1编码的字符串,向期望使用iso-8859-1的字符串的东西提供Unicode代码点的字符串将起作用(如果所有代码点位于iso-8859-1字符集中。)
问题1A:
use open IO => ':encoding(UTF-8)';
什么都不做?
这将设置open
的默认图层。例如,它使
open(my $fh, '>', $qfn)
等同于
open(my $fh, '>:encoding(UTF-8)', $qfn)
由于不使用没有默认图层的open
,因此根本不使用open
,因此没有效果。
问题1B:为什么2中的字符不能正确显示?
您的终端需要UTF-8。
使用UTF-8($str1
)编码的字符串包含终端所期望的内容,因此可以正确显示。
使用iso-8859-1($str2
)编码的字符串不符合终端的预期,因此显示不正确。
问题2:为什么这会使latin-1字符串正确显示,但破坏了UTF8字符串?
您在STDOUT中添加了:encoding(UTF-8)
层,因此现在期望打印到STDOUT的字符串包含Unicode代码点,并且它们将使用UTF-8进行编码。
使用UTF-8($str1
)编码的字符串不包含print
所期望的字符串,因此已被整顿。 (具体来说,它以“双重编码”结尾。)
Unicode代码点($str2
)的字符串由print
所期望的组成,因此它被正确编码。
问题3:我猜fix_latin指示该字符串是utf8,因此该字符串可以正确打印。
内部表示形式(如is_utf8
所示)与此处无关(应该如此)。
fix_latin("1 = educa\x{c3}\x{a7}\x{c3}\x{a3}o")
产生了"1 = educa\x{e7}\x{e3}o"
。
fix_latin("2 = educa\x{e7}\x{e3}o")
产生了"2 = educa\x{e7}\x{e3}o"
。