为什么我不能使用地图功能,从在Perl一个简单的数据文件中创建一个好的哈希?

StackOverflow https://stackoverflow.com/questions/1762977

  •  21-09-2019
  •  | 
  •  

<强>的交被更新。敬请跳转到解决方案的一部分,如果你已经阅读贴出的问题。谢谢!

下面是最小化的代码表现出我的问题:

用于测试输入数据文件已被保存通过窗口的内置记事本为UTF-8编码。 它具有以下三行:

abacus  æbәkәs
abalone æbәlәuni
abandon әbændәn

在Perl脚本文件也被保存通过窗口的内置记事本为UTF-8编码。 它包含以下代码:

#!perl -w

use Data::Dumper;
use strict;
use autodie;
open my $in,'<',"./hash_test.txt";
open my $out,'>',"./hash_result.txt";

my %hash = map {split/\t/,$_,2} <$in>;
print $out Dumper(\%hash),"\n";
print $out "$hash{abacus}";
print $out "$hash{abalone}";
print $out "$hash{abandon}";

在输出中,哈希表似乎是好:

$VAR1 = {
          'abalone' => 'æbәlәuni
',
          'abandon' => 'әbændәn',
          'abacus' => 'æbәkәs
'
        };

但实际上不是,因为我只得到两个值,而不是三个:

æbәlәuni
әbændәn

的Perl给出以下警告消息:

Use of uninitialized value $hash{"abacus"} in string at C:\test2.pl line 11, <$i n> line 3.

其中的问题?可有人好心解释一下吗?感谢。

<强>解决方案

感谢所有你们的百万:)现在终于罪魁祸首被发现,问题就可以解决的:) 作为@Sinan深刻地指出,现在我100%肯定,对我造成上述问题的罪魁祸首是两个字节BOM,这记事本添加到我的数据文件时,它被保存为UTF-8,这在某种程度上的Perl不能正确对待。虽然很多建议,我应该使用“<:UTF8”和“>:UTF8”读写文件时,就是这些UTF8配置不解决问题。相反,他们可能会造成一些其它的问题。

要真正解决问题,所有我真正需要的是添加一行代码,以强制Perl忽略BOM:

#!perl -w

use Data::Dumper;
use strict;
use autodie;

open my $in,'<',"./hash_test.txt";
open my $out,'>',"./hash_result.txt";

seek $in,3,0; # force Perl to ignore the BOM!
my %hash = map {split/\t/,$_,2} <$in>;
print $out Dumper(\%hash);
print $out $hash{abacus};
print $out $hash{abalone};
print $out $hash{abandon};

现在,输出正是我预期:

$VAR1 = {
          'abalone' => 'æbәlәuni
',
          'abandon' => 'әbændәn',
          'abacus' => 'æbәkәs
'
        };
æbәkәs
æbәlәuni
әbændәn

请注意,脚本被保存为UTF-8编码和代码不必包含任何UTF-8标签,因为输入文件和输出文件都预先保存为UTF-8编码。

最后,再次感谢各位。谢谢你,@Sinan,为精辟的指导意见。没有你的帮助,我会留在黑暗中神不知过了多久。

注意 为了澄清多一点,如果我使用:

open my $in,'<:utf8',"./hash_test.txt";
open my $out,'>:utf8',"./hash_result.txt";

my %hash = map {split/\t/,$_,2} <$in>;
print $out Dumper(\%hash);
print $out $hash{abacus};
print $out $hash{abalone};
print $out $hash{abandon};

的输出是这样的:

$VAR1 = {
          'abalone' => "\x{e6}b\x{4d9}l\x{4d9}uni
",
          'abandon' => "\x{4d9}b\x{e6}nd\x{4d9}n",
          "\x{feff}abacus" => "\x{e6}b\x{4d9}k\x{4d9}s
"
        };
æbәlәuni
әbændәn

和警告消息:

Use of uninitialized value in print at C:\hash_test.pl line 13,  line 3.
有帮助吗?

解决方案

我找到该警告消息一点可疑。它告诉你,$in文件句柄是在3线时它应该具有读取的最后一行之后是在4行。

当我想你的代码,我救了使用这是我的系统,以保存为UTF-8上配置gVim的输入文件,我没有看到这个问题。现在,我试了一下,用记事本,看着输出文件,我看到:

"\x{feff}abacus" => "\x{e6}b\x{4d9}k\x{4d9}s
"

其中\x{feff} BOM

在您的自卸车输出,有abacus之前虚假空白(你没有指定:utf8的输出句柄)。

由于我原本(失去这个帖子上的许许多多的编辑 - 感谢您的提醒霍布斯)提到,指定当您打开输入文件'<:utf8'

其他提示

如果你想读/写UTF8的文件,你应该确保你实际上是阅读他们为的 UTF8

#! /usr/bin/env perl
use Data::Dumper;
open my $in,  '<:utf8', "hash_test.txt";
open my $out, '>:utf8', "hash_result.txt";

my %hash = map { chomp; split ' ', $_, 2 } <$in>;
print $out Dumper(\%hash),"\n";
print $out "$hash{abacus}\n";
print $out "$hash{abalone}\n";
print $out "$hash{abandon}\n";

如果您希望它是更稳健,建议使用:encoding(utf8)而不是:utf8,用于读取文件。

open my $in, '<:encoding(utf8)', "hash_test.txt";

读取 PerlIO的获得更多的信息。

我觉得你的答案可能会坐在你的面前。从Data::Dumper您张贴的输出是:

$VAR1 = {
          'abalone' => 'æbәlәuni
',
          'abandon' => 'әbændәn',
          'abacus' => 'æbәkәs
'
        };

注意'abacus之间的字符?您试图通过$hash{abacus}访问的第三值。这是因为在abacus哈希Dumper()之前字符不正确。你可以尝试插到一个循环应该照顾它:

foreach my $k (keys %hash) {
  print $out $hash{$k};
}

拆分/ \ S /代替拆分/ \吨/

我的作品。你确定你的榜样实际代码和数据匹配?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top