Perl представляет внутренности в виде строки

Как делают строки жемчуга, представленные внутренне? Какое кодирование используется? Как я обрабатываю различную кодировку правильно?

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

До этого момента я думал о строках жемчуга как последовательности байтов, которые действительно соответствовали вполне прилично для моих задач. Теперь я должен сделать, некоторая обработка UTF-8 закодировала файл и здесь запускает проблему.

Во-первых, я считал файл в строку как это:

open(my $in, '<', $ARGV[0]) or die "cannot open file $ARGV[0] for reading";
binmode($in, ':utf8');

my $contents;

{
    local $/;
    $contents = <$in>;
}

close($in);

затем просто распечатайте его:

print $contents;

И я получаю две вещи: предупреждение Wide character in print at <scriptname> line <n> и мусор в консоли. Таким образом, я могу прийти к заключению, что строки жемчуга имеют понятие "символа", который может быть "широким" или нет, но при печати эти "широкие" символы представлены в консоли как несколько байтов, не как единственный "символ". (Интересно теперь, почему сделал весь мой предыдущий опыт с двоичными файлами, работавшими вполне, как я ожидал, что это будет работать без каких-либо "символьных" проблем).

Почему затем я вижу мусор в консоли? Если жемчуг хранит строки как символ в некотором известном кодировании, я не думаю, что существует большая проблема для обнаружения консольного текста кодирования и печати правильно. (Я использую Windows, BTW).

Если жемчуг хранит строки как последовательности символов переменной ширины (например, использующий ту же кодировку UTF-8), почему это сделано этот путь? На основе моего опыта C, обрабатывающего строки, БОЛЬ.

Обновление.

Я использую два компьютера для тестирования, каждый запускает Windows 7 x64 с английским установленным пакетом языка, но с российскими региональными настройками (таким образом, у меня есть cp866 как кодовая страница OEM и cp1251 как ANSI) с ActivePerl 5.10.1 x64; другой выполняет Windows XP российская локализация на 32 бита с Perl Cygwin 5.10.0.

Благодаря ссылкам теперь у меня есть намного более основательное понимание того, что продолжается и как должны быть сделаны вещи.

8
задан n0rd 3 June 2010 в 17:31
поделиться

3 ответа

Установка utf8 перед чтением из файла - это хорошо, она автоматически декодирует байты во внутреннюю кодировку. (Это также UTF-8, но вам не нужно знать и не следует полагаться на него.)

Перед печатью вам необходимо снова закодировать символы в байты.

use Encode;  
utf8::encode($contents);

Существует также форма кодирования с двумя аргументами для кодировок, отличных от Unicode. (В этом предложении слишком много эха, не так ли?)

Вот хорошая ссылка. (Было бы больше, но это мой первый пост.) Также ознакомьтесь с perlunitut и статьей в Юникоде о Джоэле о программном обеспечении.

http://www.ahinea.com/en/tech/perl-unicode-struggle.html

О, и он должен использовать многобайтовые строки, потому что в противном случае это не юникод.

4
ответ дан 5 December 2019 в 17:34
поделиться

Вы должны указать ваши актуальные версии Windows и Perl, поскольку это действительно зависит от используемых вами версий и установленных языковых пакетов.
В противном случае сначала посмотрите руководство PerlUnicode -

Perl использует логически широкие символы для внутреннего представления строк.

он подтвердит ваши утверждения.

Windows не полностью устанавливает все символы UTF8 - это может быть причиной вашей проблемы. Возможно, вам потребуется установить дополнительный языковой пакет.

2
ответ дан 5 December 2019 в 17:34
поделиться

Строки Perl хранятся внутри в одной из двух кодировок: либо 8-битная собственная кодировка, ориентированная на байты, либо UTF-8. Для обратной сопоставимости предполагается, что все операции ввода-вывода и строки находятся в собственной кодировке, если не указано иное. Собственная кодировка обычно 8-битный ASCII, но это можно изменить с помощью use locale .

В вашем примере вы вызываете binmode для своего дескриптора ввода, изменяя его для использования семантики : utf8 . Одним из следствий этого является то, что все строки, считываемые из этого дескриптора, будут закодированы как UTF-8. print по умолчанию записывает в STDOUT , а STDOUT по умолчанию ожидает символов в собственном кодировании.

Perl, пытаясь поступить правильно, позволяет отправлять строку UTF-8 на собственный кодированный вывод, но если к этому дескриптору не прикреплена кодировка, он должен угадать, как выводить многобайтовые символы. и он почти наверняка угадает неверно. Вот что означает предупреждение: многобайтовый символ был отправлен в поток, ожидающий только однобайтовых символов, и в результате этот символ, вероятно, был поврежден при переводе.

В зависимости от того, что вы хотите достичь, вы можете использовать модуль Encode, упомянутый Диланом, для преобразования данных UTF-8 в однобайтовый набор символов, который можно безопасно распечатать, или если вы знаете, что все, что прикреплено к STDOUT может обрабатывать UTF-8, вы можете использовать binmode (STDOUT, ': utf8'); , чтобы сообщить Perl, что вы хотите, чтобы любые данные, отправляемые в STDOUT , отправлялись как UTF-8 .

4
ответ дан 5 December 2019 в 17:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: