perl - исправление смешанного кодирования utf8 и латиницы: используйте открытый ввод-вывод против binmode - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть файл хранения perl, в котором (при дампере с Dumper) есть следующие строки:

my $str1 = "1 = educa\x{c3}\x{a7}\x{c3}\x{a3}o";
my $str2 =  "2 = educa\x{e7}\x{e3}o";

Я пытался выработать разумную стратегию для вывода UTF8 (см. Также Perl Encode :: Угадай с подсказками и без них - обнаружение utf8 ).

Позвольте мне продолжить с приведенным выше кодом Perl и получить несколько объявлений:

use 5.18.2;
use Encode qw( encode_utf8 decode_utf8 from_to encode decode);
use Encode::Guess;
use Encoding::FixLatin qw(fix_latin);

sub sayStrings() {
    say fixEnc($_[0]);
    say fixEnc($_[1],'hint');
    say "";
};

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

Теперь на вопросы! Я собираюсь дополнить этот код различными фрагментами.

say "Question 1";
&sayStrings($str1, $str2);

и

use open IO => ':encoding(UTF-8)';
say "raw";
&sayStrings($str1, $str2);

оба дают:

Question 1
1 = educação; encoding: utf8, is_utf8=, valid=1
2 = educa??o; encoding: iso-8859-1, is_utf8=, valid=1

Вопрос 1А: Что use open IO => ':encoding(UTF-8)'; ничего не делает? Я предполагаю, что моя система уже настроена как UTF8. Правильно?

Вопрос 1B: Почему символы в 2 отображаются неправильно? Кодировка определяется правильно, но, может быть, когда строка выводится в UTF, 'çã' становятся символами UTF, о которых система не знает (или их нет)?

Теперь к вопросу 2:

use open IO => ':encoding(UTF-8)',':std';
say "Question 2";
&sayStrings($str1, $str2);

дает:

Question 2
1 = educação; encoding: utf8, is_utf8=, valid=1
2 = educação; encoding: iso-8859-1, is_utf8=, valid=1

Вопрос 2: Почему это заставляет строку latin-1 отображаться корректно, но прерывать строку UTF8? (Т.е. кажется, что при добавлении: std последовательность символов в str1 интерпретируется как latin-1, а не UFT8, см. perl Encode :: Guess с и без подсказок - обнаружение utf8 ). Почему это так?

Вопрос 3:

use open IO => ':encoding(UTF-8)',':std';
say "fix_latin";
&sayStrings(&fix_latin($str1), &fix_latin($str2));

дает

fix_latin
1 = educação; encoding: utf8, is_utf8=1, valid=1
2 = educação; encoding: utf8, is_utf8=1, valid=1

Вопрос 3: я думаю, что fix_latin указывает, что строка - utf8, и поэтому строка печатается правильно. Так что, очевидно, я чего-то не понимаю в том, чтобы подписать строку как utf8 и binmode. Что это?

Большое спасибо!

(П.С. пытался прочитать документы по этому вопросу, но да, пожалуйста, отправьте ссылки, которые объяснят это - в идеале на понятном языке с большим количеством примеров ...)

1 Ответ

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

Во-первых, вы должны понимать, что $str2 можно рассматривать как строку, закодированную с помощью iso-8859-1, и это также строка кодовых точек Unicode. Это потому, что строка, закодированная с использованием iso-8859-1, ничем не отличается от строки кодовых точек Unicode. Например, decode('iso-8859-1', $str) производит $str. Это означает, что предоставление строки, кодированной с использованием iso-8859-1, для чего-то, ожидающего строку кодовых точек Unicode, будет работать, а предоставление строки кодов Unicode для чего-то, ожидающего строку, кодированную с использованием iso-8859-1, будет работать (если все кодовые точки находятся в наборе символов iso-8859-1).


Вопрос 1А: Что use open IO => ':encoding(UTF-8)'; ничего не делает?

Устанавливает слои по умолчанию для open. Например, это составляет

open(my $fh, '>', $qfn)

эквивалентно

open(my $fh, '>:encoding(UTF-8)', $qfn)

Поскольку вы не используете open без слоев по умолчанию & mdash; вы вообще не используете open & mdash; это не имеет никакого эффекта.


Вопрос 1B: Почему символы в 2 отображаются неправильно?

Ваш терминал ожидает UTF-8.

Строка, закодированная с использованием UTF-8 ($str1), состоит из того, что ожидает терминал, поэтому она отображается правильно.

Строка, закодированная с использованием iso-8859-1 ($str2), не состоит из того, что ожидает терминал, поэтому она отображается неправильно.


Вопрос 2: Почему это заставляет строку latin-1 отображаться правильно, но прерывать строку UTF8?

Вы добавили слой :encoding(UTF-8) в STDOUT, поэтому теперь ожидается, что строки, напечатанные в STDOUT, состоят из кодовых точек Unicode, и они будут кодироваться с использованием UTF-8.

Строка, закодированная с использованием UTF-8 ($str1), не состоит из того, что ожидает print, поэтому она искажена. (Конкретно это заканчивается "двойным кодированием")

Строка кодовых точек Unicode ($str2) состоит из того, что ожидает print, поэтому она кодируется правильно.


Вопрос 3. Полагаю, что fix_latin указывает, что строка имеет вид utf8, и поэтому строка печатается правильно.

Внутреннее представление (как указано is_utf8) здесь не имеет значения (как и должно быть).

fix_latin("1 = educa\x{c3}\x{a7}\x{c3}\x{a3}o") произведено "1 = educa\x{e7}\x{e3}o".

fix_latin("2 = educa\x{e7}\x{e3}o") произведено "2 = educa\x{e7}\x{e3}o".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...