В Perl, как я могу проверить, действительно ли кодировка, указанная в строке?
Скажем, у меня есть sub, который получает два аргумента: спецификация кодирования и путь к файлу. Затем субпользователь использует эту информацию, чтобы открыть файл для чтения, как показано ниже, разделенный до его сути:
run({
encoding => 'UTF-16---LE',
input_filename => 'test_file.txt',
});
sub run {
my $args = shift;
my ($enc, $fn) = @{ $args }{qw(encoding input_filename)};
my $is_ok = open my $in,
sprintf('<:encoding(%s)', $args->{encoding}),
$args->{input_filename}
;
}
Теперь это кричит:
Cannot find encoding "UTF-16---LE" at E:\Home\...
Что такое right, чтобы гарантировать, что $args->{encoding}
содержит допустимую спецификацию кодирования перед интерполяцией во второй аргумент на open
?
Update
Информация ниже представлена в надежде, что в какой-то момент она будет полезна кому-то. Я также собираюсь записать отчет об ошибке .
В документах для Encode::Alias вообще не упоминается find_alias
. Случайный взгляд на Encode/Alias.pm
в моей системе Windows показывает:
# Public, encouraged API is exported by default
our @EXPORT =
qw (
define_alias
find_alias
);
Однако обратите внимание:
#!/usr/bin/env perl
use 5.014;
use Encode::Alias;
say find_alias('UTF-8')->name;
дает:
Use of uninitialized value $find in exists at C:/opt/Perl/lib/Encode/Alias.pm line 25.
Use of uninitialized value $find in hash element at C:/opt/Perl/lib/Encode/Alias.pm line 26.
Use of uninitialized value $find in pattern match (m//) at C:/opt/Perl/lib/Encode/Alias.pm line 31.
Use of uninitialized value $find in lc at C:/opt/Perl/lib/Encode/Alias.pm line 40.
Use of uninitialized value $find in pattern match (m//) at C:/opt/Perl/lib/Encode/Alias.pm line 31.
Use of uninitialized value $find in lc at C:/opt/Perl/lib/Encode/Alias.pm line 40.
Быть 1) ленив и 2) сначала предположить, что я делаю что-то неправильно, я решил искать чужую мудрость.
В любом случае ошибка связана с тем, что find_alias
экспортируется как функция, не проверяя это в коде:
sub find_alias {
require Encode;
my $class = shift;
my $find = shift;
unless ( exists $Alias{$find} ) {
Если find_alias
не используется как метод, аргумент теперь находится в $class
и $find
равен undefined.
НТН.
Ответы
Ответ 1
Вы можете использовать функцию find_encoding
в Encode. Хотя, если вы хотите использовать его как слой :encoding
, вы также должны проверить perlio_ok
. Возможно (но редко) для кодирования, но не поддерживает использование с :encoding
:
use Carp qw(croak);
use Encode qw(find_encoding);
sub run {
my $args = shift;
my $enc = find_encoding($args->{encoding})
or croak "$args->{encoding} is not a valid encoding";
$enc->perlio_ok or croak "$args->{encoding} does not support PerlIO";
my $is_ok = open my $in,
sprintf('<:encoding(%s)', $enc->name),
$args->{input_filename}
;
}
Примечание: find_encoding
обрабатывает псевдонимы, определенные в Encode:: Alias.
Если вам не нужно различать несуществующие кодировки и те, которые не поддерживают :encoding
, вы можете просто использовать функцию perlio_ok
:
Encode::perlio_ok($args->{encoding}) or croak "$args->{encoding} not supported";
Ответ 2
Encode::Alias->find_alias($encoding_name)
возвращает объект, чей атрибут name
является именем канонической кодировки при успешном завершении, и false при ошибке.
$ Encode::Alias->find_alias('UTF-16---LE')
$ Encode::Alias->find_alias('UTF-16 LE')
Encode::Unicode {
Parents Encode::Encoding
Linear @ISA Encode::Unicode, Encode::Encoding
public methods (6) : bootstrap, decode, decode_xs, encode, encode_xs, renew
private methods (0)
internals: {
endian "v",
Name "UTF-16LE",
size 2,
ucs2 ""
}
}
$ Encode::Alias->find_alias('Latin9')
Encode::XS {
public methods (9) : cat_decode, decode, encode, mime_name, name, needs_lines, perlio_ok, renew, renewed
private methods (0)
internals: 140076283926592
}
$ Encode::Alias->find_alias('UTF-16 LE')->name
UTF-16LE
$ Encode::Alias->find_alias('Latin9')->name
iso-8859-15