为什么我的Perl程序因Tie :: File和Unicode / UTF失败
我正在研究一个处理外语数据的项目。 我的Perl脚本运行良好。
然后我想使用Tie :: File,因为这是一个简洁的概念(并且节省了时间和编码)。
似乎Tie:File在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 DocumentsTechnicalPerlEclipse workspaceWork'.
'Tie File test res.txt';
tie @Tied, 'Tie::File', $FileName, recsep => "x0Dx0A", 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 xA4xΘέλωxA8x
15
16
17
18
19
请注意,前10行是确定的,但第10到第19行来自任何地方!? 另外,绑定文件的输出包含损坏的数据:
τι κάνϏN͏Ŏՠτήστε של חברءbc לؗܗࠗܗߠeמתולאן This is מעיו לעכ؎Ďώݎ֏ναι ΤρΘέώގѠφϏŎ٠κτε;שרה מס'
xA4xΘέλωxA8x
这里有点不对劲。 要么我错过了某些东西,要么Tie:File无法应付Unicode / UTF-8? 我在Windows 7系统上运行Strawberry Perl 5.14。
许多TIA - 海伦
注意:也张贴在http://perlmonks.org/?node_id=1002104上
我会提出的建议很大程度上取决于您尝试解决的实际问题。 单独看这个问题,我不会有太多的编码/解码“魔术”,只会使用原始字节(因为脚本不需要知道任何关于这个任务的角色本身)。 下面给出你所描述的输入和输出的预期结果。
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 => "x0Dx0A" 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;
但是 ,您可能确实想对中间的文本进行一些处理。 在这种情况下,你需要解码字符。 正如我所看到的,有两种选择:
数字2可能不是微不足道的 - 对Tie :: File源的快速扫描,它看起来像假定它总是会给出字节。 你可以看到唯一影响的部分是https://metacpan.org/source/TODDR/Tie-File-0.98/lib/Tie/File.pm#L111中的binmode - 你正在做的。
Tie :: File做了很多seek
调用,perldoc在seek(http://perldoc.perl.org/functions/seek.html)上有这样的说法:
请注意以字节为单位:即使文件句柄已设置为对字符进行操作(例如,通过使用:encoding(utf8)开放图层),tell()将返回字节偏移量,而不是字符偏移量(因为执行该操作会呈现seek )并且告诉()相当慢)。
所以看来,Tie :: File正在使用字符长度来确定记录的字节偏移量。 因此它可能会以UTF-8字符序列的中间结束。 这似乎是您的错误的可能原因。
一般来说,当依靠外部模块读取/写入文件句柄时,我远离binmode
- 在这种情况下,我会在一个简单的子调用Encode::encode('UTF-8', ...)
数据推入@tied之前。
例外情况是模块的文档清楚地说明了解码数据的行为,或者源码足够简单,可以验证行为。
链接地址: http://www.djcxy.com/p/11371.html上一篇: Why is my Perl program failing with Tie::File and Unicode/UTF