我正在从事一个处理外语数据的项目。我的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 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行却无处可来!
此外,绑定(bind)文件的输出包含损坏的数据:
 τι κάνϏN͏Ŏՠτήστε של חברءbc לؗܗࠗܗߠeמתולאן This is מעיו לעכ؎Ďώݎ֏ναι ΤρΘέώގѠφϏŎ٠κτε;שרה מס'



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

这里出了点问题。我丢失了什么,还是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 => "\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;

但是,您可能确实想对中间的文本进行一些处理。在这种情况下,您需要解码的字符。在我看来,有两种选择:
  • 手动编码,然后再切换到绑定(bind)数组
  • 找出Tie::File
  • 的问题是什么

    数字2可能是不平凡的-快速扫描Tie::File源,并且看起来它假定将始终被赋予字节。您似乎可以影响的唯一部分是https://metacpan.org/source/TODDR/Tie-File-0.98/lib/Tie/File.pm#L111中的binmode-您正在执行的操作。

    Tie::File进行了许多seek调用,perldoc在搜索(http://perldoc.perl.org/functions/seek.html)时有这样的说法:



    因此,看来Tie::File使用字符长度来确定其记录的字节偏移量。因此,它可能会出现在UTF-8字符序列的中间。这似乎是造成您的错误的原因。

    通常,当依靠外部模块读取/写入文件句柄时,我会远离binmode-在这种情况下,在推送到@tied之前,我将对数据进行简单的子调用Encode::encode('UTF-8', ...)

    异常(exception)情况是,模块的文档中明确说明了解码数据的行为,或者该源足够简单,我无法验证其行为。

    关于perl - 为什么我的Perl程序以Tie::File和Unicode/UTF-8编码失败?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13209474/

    10-12 06:58