【问题标题】:perl - fixing mixed utf8 and latin encoding: use open IO vs. binmodeperl - 修复混合 utf8 和拉丁编码:使用开放 IO 与 binmode
【发布时间】:2019-04-08 13:14:45
【问题描述】:

我有一个 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;
    };
};

现在回答问题!我将用各种 sn-ps 来补充该代码。

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. 已尝试阅读有关此的文档,但是是的,请发送可以解释这一点的链接 - 最好用清晰的语言和大量示例...)

【问题讨论】:

    标签: perl utf-8


    【解决方案1】:

    首先,您必须意识到$str2 可以被视为使用iso-8859-1 编码的字符串,它也是一个Unicode 代码点字符串。这是因为使用 iso-8859-1 编码的字符串与 Unicode 代码点字符串没有什么不同。例如,decode('iso-8859-1', $str) 产生 $str。这意味着将使用 iso-8859-1 编码的字符串提供给期望 Unicode 代码点字符串的东西将起作用,并且将 Unicode 代码点字符串提供给期望使用 iso-8859-1 编码的字符串将起作用(如果所有代码点在 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"

    【讨论】:

    • 谢谢 - 我看过这个,它帮助我更好地理解这个!
    猜你喜欢
    • 2018-02-14
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多