Perl Encode :: Угадай с и без подсказок - обнаружение utf8 - PullRequest
0 голосов
/ 05 ноября 2018

Я запутался в Encode :: Guess. Предположим, это мой Perl-код:

use strict; 
use warnings;
use 5.18.2;
use Encode;
use Encode::Guess qw/utf8 iso-8859-1/;
use open IO => ':encoding(UTF-8)', ':std';
my $str1 = "1 = educa\x{c3}\x{a7}\x{c3}\x{a3}o";
my $str2 =  "2 = educa\x{e7}\x{e3}o";

say "A: ".&fixEnc($str1);
say "B: ".&fixEnc($str1,'hint');
say "C: ".&fixEnc($str2);
say "D: ".&fixEnc($str2,'hint');
say "";

sub fixEnc() {
    my $data = $_[0];
    my $enc = "";
    if ($_[1]) {
        $enc = guess_encoding($data,qw/utf8 iso-8859-1/);
    } else {
        $enc = guess_encoding($data);
    };
    if (!ref($enc)) {
        return "ERROR: Can't guess: $enc for $data";
    } else {
        my $utf8 = decode($enc->name, $data);
        $utf8 = "encoding guess: ".$enc->name."; result: $utf8";
        return $utf8;
    };
};

Производит:

A1: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação
B2: ERROR: Can't guess: utf8 or iso-8859-1 for 1 = educação
C1: encoding guess: iso-8859-1; result: 2 = educação
D1: encoding guess: iso-8859-1; result: 2 = educação

Теперь, если я заменю 'используйте Encode :: Guess qw / utf8 iso-8859-1 /;' используя 'Encode :: Guess;' Я получаю

A2: encoding guess: utf8; result: 1 = educação
B2: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação
C2: ERROR: Can't guess: No appropriate encodings found! for 2 = educação
D2: encoding guess: iso-8859-1; result: 2 = educação

Что вызывает разницу? В частности, почему utf8 не угадывается, когда я намекаю на utf8?

Редактировать: я разместил ответ ниже. По сути, осознание того, что Guess использует кодировки символов и не говорит по-португальски! 'Educaçà £ o', хотя не на португальском языке, является правильной латиницей-1 версией строки 1 выше, которую Гесс не может отличить от версии UTF8 educação (в отличие от португальского языка).

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Я думаю, что это происходит. С use Encode::Guess qw/utf8 iso-8859-1/; «подсказка» не имеет значения (извините за неясность!), Поэтому у нас есть только

A1/B1: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação

и C1 / D1: кодовое предположение: iso-8859-1; результат: 2 = educação

Для A1 / B2 строка может быть UTF8 (educação) или латинской1 (educação o). Второй выглядит некорректно, но Encode :: Guess не может сказать - Guess использует кодировки символов и не говорит по-португальски!

Теперь, если я заменю 'используйте Encode :: Guess qw / utf8 iso-8859-1 /;' используя 'Encode :: Guess;' Я получаю

A2: encoding guess: utf8; result: 1 = educação

latin-1 больше не является опцией (она не является частью значения по умолчанию), поэтому результат получается как utf8.

B2: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação

В B2 с попаданием мы вернулись в описанном выше сценарии, и Угадай не может решить.

Для C2:

C2: ERROR: Can't guess: No appropriate encodings found! for 2 = educação

это имеет смысл, так как латиница-1 не является частью значения по умолчанию. Наконец в D2

D2: encoding guess: iso-8859-1; result: 2 = educação

намекается на латиницу-1, поэтому определяется кодировка.

0 голосов
/ 05 ноября 2018

Трудно сказать наверняка, потому что есть несколько проблем, которые затрудняют определение кодировки.

Во-первых, iso-8859-1 делит почти все свои кодовые точки с utf8. Если в начале строки нет определенной метки порядка байтов или символа, которого нет в iso-8859-1, то Encode :: Guess на самом деле просто угадывает.

Second упоминается в предостережениях Encode :: Guess в perldocs. Encode :: Guess просматривает текст, используя алгоритм «проб и ошибок», чтобы исключить все, кроме одной из предоставленных кодировок. Естественно, чем более похожи кодировки, тем менее точным будет модуль.

В-третьих, если вы не укажете разрешенные типы кодирования в операторе использования, модуль сравнит его со всем, что может. Это в сочетании с методом проб и ошибок и перекрытием в кодовых точках utf8 против iso-8859-1 означает, что для Encode :: Guess возможно сделать разные выводы на основе параметров, переданных методу. Я полагаю, вы бы получили более последовательные результаты, если бы проверили по двум другим расходящимся кодировкам, таким как utf8 против 7bit-jis.

Наконец, Perl имеет более чем одну реализацию utf8 , поэтому также возможно, что, если вы не укажете кодировку utf8 явно, он может использовать другую реализацию, которая может изменить результаты как Что ж. Я не знаю достаточно о внутренностях Perl, чтобы подтвердить, что это то, что происходит в этом случае.

...