Запись обновлена. Пожалуйста, перейдите к части «Решение», если вы уже прочитали опубликованный вопрос. Спасибо!
Вот свернутый код, демонстрирующий мою проблему:
Входной файл данных для теста был сохранен встроенным блокнотом Window в кодировке UTF-8.
Он имеет следующие три строки:
abacus æbәkәs
abalone æbәlәuni
abandon ә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 = {
'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% уверен, что виновником возникновения описанной выше проблемы являются два байта спецификации, которые Блокнот добавил в мой файл данных, когда он был сохранен как UTF-8, и который каким-то образом Perl не лечит должным образом. Хотя многие предлагали мне использовать «<: utf8» и «>: utf8» для чтения и записи файлов, дело в том, что эти конфигурации utf-8 не решают проблему. Вместо этого они могут вызвать некоторые другие проблемы.
Чтобы действительно решить проблему, все, что мне действительно нужно, это добавить одну строку кода, чтобы Perl игнорировал спецификацию:
#!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.