#perl #utf-8
#perl #utf-8
Вопрос:
У меня есть программа Perl 5.30.0 на Ubuntu, где комбинация File::Slurp
и open ':std', ':encoding(UTF-8)'
приводит к неправильному чтению UTF8:
use strict;
use warnings;
use open ':std', ':encoding(UTF-8)';
use File::Slurp;
my $text = File::Slurp::slurp('input.txt');
print "$textn";
с помощью «input.txt » является текстовым файлом в кодировке UTF8 с таким содержимым (без спецификации).:
ö
Когда я запускаю это, ö
отображается как ö
. Только когда я удаляю use open...
строку, она работает должным образом и ö
печатается как ö
.
Когда я вручную читаю файл, как показано ниже, все работает так, как ожидалось, и я получаю ö
:
$text = '';
open my $F, '<', "input.txt" or die "Cannot open file: $!";
while (<$F>) {
$text .= $_;
}
close $F;
print "$textn";
Почему это так и как лучше всего поступить здесь? Является open
ли прагма устаревшей или я что-то еще упускаю?
Ответ №1:
Как и во многих прагмах, [1] эффект use open
лексически ограничен.[2] Это означает, что он влияет только на оставшуюся часть блока или файла, в котором он найден. Такая прагма не влияет на код в функциях за пределами ее области видимости, даже если они вызываются из этой области видимости.
Вам нужно сообщить о желании декодировать поток в File::Slurp. Это невозможно сделать с помощью slurp
, но это можно сделать read_file
с помощью его binmode
параметра.
use open ':std', ':encoding(UTF-8)'; # Still want for effect on STDOUT.
use File::Slurp qw( read_file );
my $text = read_file('input.txt', { binmode => ':encoding(UTF-8)' });
Лучшим модулем является File::Slurper .
use open ':std', ':encoding(UTF-8)'; # Still want for effect on STDOUT.
use File::Slurper qw( read_text );
my $text = read_text('input.txt');
File::Slurper read_text
по умолчанию использует декодирование с использованием UTF-8.
Без модулей вы могли бы использовать
use open ':std', ':encoding(UTF-8)';
my $text = do {
my $qfn = "input.txt";
open(my $F, '<', $qfn)
or die("Can't open file "$file": $!n");
local $/;
<$fh>
};
Конечно, это не так ясно, как предыдущие решения.
- Другие известные примеры включают
use VERSION
,use strict
,use warnings
,use feature
иuse utf8
. - Влияние на STDIN, STDOUT и STDERR из
:std
является глобальным.
Комментарии:
1. Предупреждение об опечатке: похоже, вы хотели вставить
<$F>
последнюю строку блока do в вашем примере немодульного подхода.
Ответ №2:
На самом деле это не ответ на ваш вопрос, но мой любимый модуль ввода-вывода файлов в наши дни — Path::Tiny .
use Path::Tiny;
my $text = path('input.txt')->slurp_utf8;