Unicode беспорядок строки в Perl - PullRequest
3 голосов
/ 07 октября 2010

У меня есть внешний модуль, который возвращает мне несколько строк.Я не уверен, как именно возвращаются строки.Я действительно не знаю, как работают строки Unicode и почему.

Модуль должен возвращать, например, чешское слово «být», что означает «быть».(Если вы не видите вторую букву - она ​​должна выглядеть как this .) Если я отображаю строку, возвращаемую модулем, с помощью Data Dumper, я вижу ее как b\x{fd}t.

* 1007.* Однако, если я попытаюсь напечатать его с print $s, я получу предупреждение «Широкий символ в печати», и?вместо ý.

Если я попытаюсь Encode::decode(whatever, $s);, результирующая строка не может быть напечатана в любом случае (всегда с предупреждением «Широкий символ», иногда с искаженными символами, иногда справа), независимо от того, что я вставил в whatever.

Если я попытаюсь Encode::encode("utf-8", $s);, полученная строка МОЖЕТ быть напечатана без проблем или сообщений об ошибках.

Если я использую use encoding 'utf8';, печать работает без необходимости кодирования /декодирования. Однако , если я использую модуль IO::CaptureOutput или Capture::Tiny, он снова начинает выкрикивать "Широкий символ".

У меня есть несколько вопросов, в основном о том, что именно происходит.(Я пытался читать perldocs, но я был не очень мудр от них)

  1. Почему я не могу напечатать строку сразу после ее получения из модуля?
  2. Почему можно 'я печатаю строку, расшифрованную как «декодировать»?Что именно "декодировал" сделал?
  3. Что именно "кодировал" сделал, и почему не было проблем с его печатью после кодирования?
  4. Что именно use encoding делает?Почему кодировка по умолчанию отличается от utf-8?
  5. Что мне нужно делать, если я хочу печатать скаляры без проблем, даже когда я хочу использовать один из модулей захвата?

edit: Некоторые люди говорят мне использовать -C или binmode или PERL_UNICODE.Это отличный совет.Тем не менее, каким-то образом оба модуля захвата волшебным образом уничтожают UTF8-ность STDOUT.Кажется, это скорее ошибка модулей, но я не совсем уверен.

edit2: ОК, лучшим решением было бы сбросить модули и написать «захват» сам (с гораздо меньшей гибкостью).

Ответы [ 3 ]

5 голосов
/ 07 октября 2010
  1. Поскольку вы выводите строку во внутренней форме perl (utf8) в файловый дескриптор не-Unicode.
  2. Функция decode декодирует последовательность байтов, которая, как предполагается, находится в ENCODING, во внутреннюю форму Perl(utf8).Ваш ввод, кажется, уже декодирован,
  3. Функция encode() кодирует строку из внутренней формы Perl в ENCODING.
  4. Прагма encoding позволяет вам писать скрипт в любой кодировке, которую вы используете.лайк.Строковые литералы автоматически преобразуются во внутреннюю форму perl.
  5. Убедитесь, что perl знает, какая кодировка ваших данных входит и выходит.

См. Также perluniintro, perlunicode, Encode module, binmode () функция.

3 голосов
/ 08 октября 2010

Я рекомендую прочитать главу моей книги по Unicode Эффективное программирование на Perl .Мы собрали все документы, которые смогли найти, и объяснили Unicode в Perl гораздо более согласованно, чем я видел где-либо еще.

Эта программа прекрасно работает для меня:

#!perl

use utf8;
use 5.010;

binmode STDOUT, ':utf8';

my $string = return_string();

say $string;

sub return_string { 'být' }

Кроме того, Capture :: Tiny прекрасно работает для меня:

#!perl
use utf8;
use 5.010;
use Capture::Tiny qw(capture);

binmode STDOUT, ':utf8';

my( $stdout, $stderr ) = capture {
    system( $^X, '/Users/brian/Desktop/czech.pl' );
    };

say "STDOUT is [$stdout]";

IO :: CaptureOutput , похоже, есть некоторые проблемы:

#!perl
use utf8;
use 5.010;
use IO::CaptureOutput qw(capture);

binmode STDOUT, ':utf8';

capture {
    system( $^X, '/Users/brian/Desktop/czech.pl' );
    } \my $stdout, \my $stderr;

say "STDOUT is [$stdout]";

За это я получаю:

STDOUT is [být
]

Однако это легко исправить.Не используйте этот модуль.:)

1 голос
/ 07 октября 2010

Вам также следует взглянуть на переменную окружения PERL_UNICODE , которая аналогична использованию опции -C .Это позволяет вам установить STDIN / STDOUT / STDERR (и @ARGV) в UTF-8 без необходимости изменения ваших сценариев.

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