В Perl, как я могу проверить правильность кодировки, указанной в строке? - PullRequest
10 голосов
/ 31 марта 2012

Скажем, у меня есть подпрограмма, которая получает два аргумента: спецификацию кодировки и путь к файлу. Подпрограмма затем использует эту информацию, чтобы открыть файл для чтения, как показано ниже, в упрощенном виде:

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\...

Каков правильный способ гарантировать, что $args->{encoding} содержит действительную спецификацию кодирования перед интерполяцией во второй аргумент open?

Обновление

Информация ниже предоставлена ​​в надежде, что она будет кому-то полезна в какой-то момент. Я также собираюсь подать отчет об ошибке .

Документы для 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 не определен.

НТН.

Ответы [ 2 ]

5 голосов
/ 31 марта 2012

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
4 голосов
/ 31 марта 2012

Вы можете использовать функцию find_encoding в Кодировать .Хотя, если вы хотите использовать его в качестве :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";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...