帖子已更新。如果您已经阅读过发布的问题,请跳到解决方案部分。谢谢!
这是展示我的问题的最小化代码:
用于测试的输入数据文件已被 Window 的内置记事本保存为 UTF-8 编码。它有以下三行:
算盘 æbәkәs 鲍鱼 æbәlәuni 放弃әbændәn
Perl 脚本文件也被 Window 的内置记事本保存为 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 = { '鲍鱼' => 'æbәlәuni ', '放弃' => 'әbændәn', '算盘' => 'æ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" 来读写文件,但问题是这些 utf-8 配置并不能解决问题。相反,它们可能会导致其他一些问题。
要真正解决这个问题,我真正需要的是添加一行代码来强制 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 = { '鲍鱼' => 'æbәlәuni ', '放弃' => 'әbændәn', '算盘' => 'æ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 = { '鲍鱼' => "\x{e6}b\x{4d9}l\x{4d9}uni ", '放弃' => "\x{4d9}b\x{e6}nd\x{4d9}n", "\x{feff}算盘" => "\x{e6}b\x{4d9}k\x{4d9}s " }; æbәlәuni әbændәn
和警告信息:
在 C:\hash_test.pl 第 13 行第 3 行的打印中使用未初始化的值。