Пост обновлен. Пожалуйста, перейдите к части решения, если вы уже прочитали опубликованный вопрос. Спасибо!
Вот минимизированный код, демонстрирующий мою проблему:
Файл входных данных для теста был сохранен встроенным блокнотом Windows в кодировке UTF-8. Он имеет следующие три строки:
abacus æbәkәs abalone æbәlәuni abandon әbændәn
Файл сценария Perl также был сохранен встроенным блокнотом Windows в кодировке 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.
chomp
внутри карты {} - person Matteo Riva   schedule 19.11.2009' abacus'
в вашем выводе Dumper (который не был виден до того, как я отредактировал ваш пост). Смотрите мой обновленный ответ. - person Sinan Ünür   schedule 19.11.2009' abacus'
— это спецификация. - person Sinan Ünür   schedule 19.11.2009