为什么我不能使用地图功能,从在Perl一个简单的数据文件中创建一个好的哈希?
-
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 /代替拆分/ \吨/
我的作品。你确定你的榜样实际代码和数据匹配?