为什么我的Perl程序与领带::文件和Unicode / UTF-8编码失败?(Why is my

2019-07-03 12:48发布

我工作的一个项目,与外国语言的数据交易。 我的Perl脚本中运行良好。

然后我想用领带::文件,因为这是一个整洁的概念(和节省时间和编码)。

看来,领带:文件下的Unicode / UTF-8失败(除非我失去了一些东西)。

这里是一个描述该问题的方案:(数据为英语,希腊语和希伯来语的混合):

use strict;
 use warnings;
 use 5.014; 
 use Win32::Console;
 use autodie; 
 use warnings qw< FATAL utf8 >;
 use Carp;
 use Carp::Always;
 use utf8;
 use feature        qw< unicode_strings>;
 use charnames      qw< :full>;
use Tie::File;

my ($i);
my ( $FileName);
my (@Tied);
binmode STDOUT, ':unix:utf8';
binmode STDERR, ':unix:utf8';
binmode $DB::OUT, ':unix:utf8' if $DB::OUT; # for the debugger
Win32::Console::OutputCP(65001);         # Set the console code page to UTF8

$FileName = 'E:\\My Documents\\Technical\\Perl\\Eclipse workspace\\Work\\'.
        'Tie File test res.txt';
tie @Tied, 'Tie::File', $FileName, recsep => "\x0D\x0A", discipline => ':encoding(utf8)'
            or confess 'tie @Tied failed';
$i =0;
while (<DATA>) {
    chomp;
    $Tied[$i] = $_;
    ++$i;
} # end while (<DATA>) 
$i =0;
foreach (@Tied) {
    say "$i $Tied[$i]";
    ++$i;
} # end foreach (@Tied)
untie $FileName;
__DATA__
τι κάνετε;
πάρτε το ή αφήστε το
שלום חברים
abc לא כןכן efg
מתי ולאן This is it
מעכשיו לעכשיו 
Σήμερα είναι Τρίτη
Θέλω να φάω
τι κάνετε;
שורה מס' 5

这将产生警告的巨大瀑布:这里是一些:

utf8 "\xCE" does not map to Unicode at F:/Win7programs/Dwimperl/perl/lib/Tie/File.pm line 917
        Tie::File::_read_record('Tie::File=HASH(0x24cb72c)') called at F:/Win7programs/Dwimper
l/perl/lib/Tie/File.pm line 175
        Tie::File::_fetch('Tie::File=HASH(0x24cb72c)', 0) called at F:/Win7programs/Dwimperl/p
erl/lib/Tie/File.pm line 210
        Tie::File::STORE('Tie::File=HASH(0x24cb72c)', 0, 'τι κάνετε;') called at tie file test
.pl line 31
utf8 "\xCF" does not map to Unicode at F:/Win7programs/Dwimperl/perl/lib/Tie/File.pm line 917
        Tie::File::_read_record('Tie::File=HASH(0x24cb72c)') called at F:/Win7programs/Dwimper
l/perl/lib/Tie/File.pm line 175
        Tie::File::_fetch('Tie::File=HASH(0x24cb72c)', 0) called at F:/Win7programs/Dwimperl/p
erl/lib/Tie/File.pm line 210
        Tie::File::STORE('Tie::File=HASH(0x24cb72c)', 0, 'τι κάνετε;') called at tie file test
.pl line 31
utf8 "\xD7" does not map to Unicode at F:/Win7programs/Dwimperl/perl/lib/Tie/File.pm line 917
        Tie::File::_read_record('Tie::File=HASH(0x24cb72c)') called at F:/Win7programs/Dwimper
l/perl/lib/Tie/File.pm line 175
        Tie::File::_fetch('Tie::File=HASH(0x24cb72c)', 0) called at F:/Win7programs/Dwimperl/p
erl/lib/Tie/File.pm line 210
        Tie::File::STORE('Tie::File=HASH(0x24cb72c)', 0, 'τι κάνετε;') called at tie file test
.pl line 31
utf8 "\xD7" does not map to Unicode at F:/Win7programs/Dwimperl/perl/lib/Tie/File.pm line 917
        Tie::File::_read_record('Tie::File=HASH(0x24cb72c)') called at F:/Win7programs/Dwimper
l/perl/lib/Tie/File.pm line 175
        Tie::File::_fetch('Tie::File=HASH(0x24cb72c)', 0) called at F:/Win7programs/Dwimperl/p
erl/lib/Tie/File.pm line 210
        Tie::File::STORE('Tie::File=HASH(0x24cb72c)', 0, 'τι κάνετε;') called at tie file test
.pl line 31

然后打印此stdout上:

0 τι κάνετε;
1 πάρτε το ή αφήστε το
2 שלום חברים
3 abc לא כןכן efg
4 מתי ולאן This is it
5 מעכשיו לעכשיו
6 Σήμερα είναι Τρίτη
7 Θέλω να φάω
8 τι κάνετε;
9 שורה מס' 5
10
11
12
13
14 \xA4\xΘέλω\xA8\x

15
16
17
18

19

注意,第一个10行是行,但行10至19从天而降!? 此外,捆绑文件的输出包含损坏的数据:

 τι κάνϏN͏Ŏՠτήστε של חברءbc לؗܗࠗܗߠeמתולאן This is מעיו לעכ؎Ďώݎ֏ναι ΤρΘέώގѠφϏŎ٠κτε;שרה מס'



\xA4\xΘέλω\xA8\x

什么是大错。 要么我失去了一些东西,或领带:文件不能使用Unicode / UTF-8应对? 我在Windows 7系统上运行的Perl草莓5.14。

许多TIA - 海伦

注:发布于http://perlmonks.org/?node_id=1002104 ,太

Answer 1:

我想提出的建议在很大程度上取决于你试图解决实际问题。 综观隔离这个问题,我不会有这么多的编码/解码“神奇”,并会简单地使用原始字节(作为脚本并不需要了解的人物亲自出手此任务)。 下面的产生给你所描述的输入和输出的预期结果。

use v5.014;
use warnings;
use autodie;

use Carp::Always;
use Tie::File;

my $file_in = 'test_in.txt';
my $file_out = 'test_tie.txt';

unlink $file_out;

tie my @tied, 'Tie::File', $file_out, recsep => "\x0D\x0A" or die 'tie failed';

open my $fh, '<', $file_in;
while (my $line = <$fh>) {
    chomp $line;
    push @tied, $line;
}
close $fh;

my $i = 0;
say $i++ . ' ' . $_ foreach @tied;

untie @tied;

然而 ,你可能想要做在中间的文本进行一些处理。 在这种情况下,你要解码的字符。 在我看来有两个选择:

  1. 换手至绑阵列之前手动编码
  2. 弄清楚这个问题是与领带::文件是什么

2号可能是不平凡的 - 的领带::文件源的快速扫描,它看起来像它假定它总是会给出字节。 你似乎可以影响只有一部分是在binmode https://metacpan.org/source/TODDR/Tie-File-0.98/lib/Tie/File.pm#L111 - 你在做什么

领带::文件做了很多seek电话,的perldoc有这对寻求(说http://perldoc.perl.org/functions/seek.html ):

请注意, 以字节为单位 :即使文件句柄已经(通过使用例如:编码(UTF8)开口层)设置的字符操作,告诉()将返回字节偏移量,而不是字符偏移量(因为执行将呈现在寻求( )告诉()相当缓慢)。

所以看来领带::文件使用字符长度来确定其记录的字节偏移。 因此,它可以以UTF-8字符序列的中间结束。 这似乎是你的错误,一个可能的原因。

在一般情况下,我从远离binmode外部模块依赖于读/写文件句柄时-在这种情况下,我想有一个简单的子调用Encode::encode('UTF-8', ...)的推到@tied之前的数据。

例外是模块的文件中明确规定对解码后的数据的行为,或者如果源是很简单的,我验证的行为。



文章来源: Why is my Perl program failing with Tie::File and Unicode/UTF-8 encoding?