Spec-Zone.ru › Perl 5.32

perlunifaq

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • В. и О.
    • perlunitut — это не совсем учебник по Unicode, не так ли?
    • Какие кодировки символов поддерживает Perl?
    • Какую версию perl следует использовать?
    • Что насчёт двоичных данных, таких как изображения?
    • Когда следует декодировать или кодировать?
    • Что если я не декодирую?
    • Что если я не кодирую?
    • Есть ли способ автоматической декодировки или кодировки?
    • Что если я не знаю, какая кодировка была использована?
    • Можно ли использовать Unicode в моих Perl-источниках?
    • Data::Dumper не восстанавливает флаг UTF8; он сломан?
    • Почему классы символов в регулярных выражениях иногда соответствуют только диапазону ASCII?
    • Почему некоторые символы не преобразуются в верхний или нижний регистр должным образом?
    • Как определить, является ли строка текстовой или двоичной?
    • Как преобразовать кодировку FOO в кодировку BAR?
    • Что такое decode_utf8 и encode_utf8?
    • Что такое «широкий символ»?
  • ВНУТРЕННЕЕ СТРОЕНИЕ
    • Что такое «флаг UTF8»?
    • Что насчёт использования псевдонима bytes?
    • Что насчёт использования псевдонима encoding?
    • В чём разница между :encoding и :utf8?
    • В чём разница между UTF-8 и utf8?
    • Я потерял след; какая кодировка используется в внутреннем формате?
  • АВТОР
  • СМОТРИТЕ ТАКЖЕ

НАЗВАНИЕ

perlunifaq — Часто задаваемые вопросы по Unicode в Perl

В. и О.

Это список вопросов и ответов о Unicode в Perl, предназначенный для прочтения после perlunitut.

perlunitut — это не совсем учебник по Unicode, не так ли?

Нет, и это не совсем FAQ по Unicode.

Perl имеет абстрагированный интерфейс для всех поддерживаемых кодировок символов, поэтому это на самом деле универсальный Encode учебник и Encode FAQ. Но многие люди считают, что Unicode — это что-то особенное и магическое, и я не хотел их разочаровывать, поэтому я решил назвать документ учебником по Unicode.

Какие кодировки символов поддерживает Perl?

Чтобы узнать, какие кодировки символов поддерживает ваш Perl, выполните:

perl -MEncode -le "print for Encode->encodings(':all')"

Какую версию perl следует использовать?

В идеале, используйте самую последнюю версию, но определённо 5.8.1 или более позднюю. В учебнике и FAQ предполагается использование последней версии.

Также следует проверить ваши модули и обновить их при необходимости. Например, HTML::Entities требует версии >= 1.32 для корректной работы, хотя в журнале изменений об этом ничего не сказано.

Что насчёт двоичных данных, таких как изображения?

По сути, помимо простого binmode $fh, их не нужно обрабатывать как-то иначе. (binmode необходим, так как в противном случае Perl может преобразовывать окончания строк в системах Win32.)

Однако будьте осторожны, никогда не комбинируйте текстовые строки с двоичными. Если вам нужно текст в двоичном потоке, сначала закодируйте текстовые строки с помощью соответствующей кодировки, а затем объедините их с двоичными данными. См. также: «Что если я не кодирую?».

Когда следует декодировать или кодировать?

Всякий раз, когда вы обмениваетесь текстом с чем-либо внешним по отношению к вашему процессу Perl, например, с базой данных, текстовым файлом, сокетом или другой программой. Даже если то, с чем вы обмениваетесь, также написано на Perl.

Что если я не декодирую?

Когда ваша закодированная двоичная строка используется вместе с текстовой строкой, Perl предположит, что ваша двоичная строка была закодирована с помощью ISO-8859-1, также известной как latin-1. Если это не latin-1, то ваши данные будут преобразовываться нежелательным образом. Например, если это был UTF-8, отдельные байты многобайтовых символов будут рассматриваться как отдельные символы, а затем снова преобразуются в UTF-8. Такую двойную кодировку можно сравнить с двойной кодировкой HTML (>) или двойной кодировкой URI (%253E).

Эта скрытая неявная декодировка называется «улучшением». Это может звучать положительно, но лучше её избегать.

Что если я не кодирую?

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

Wide character in print at example.pl line 2.

Поскольку внутренний формат часто UTF-8, эти ошибки трудно обнаружить, так как UTF-8, как правило, является требуемой кодировкой! Но не будьте ленивыми и не используйте тот факт, что внутренний формат Perl — UTF-8, себе на пользу. Кодируйте явно, чтобы избежать странных ошибок, и показать программистам, что вы всё это обдумали.

Есть ли способ автоматической декодировки или кодировки?

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

Вы можете предоставить этот слой при open файле:

open my $fh, '>:encoding(UTF-8)', $filename;  # auto encoding on write
open my $fh, '<:encoding(UTF-8)', $filename;  # auto decoding on read

Или, если у вас уже есть открытый дескриптор файла:

binmode $fh, ':encoding(UTF-8)';

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

Что если я не знаю, какая кодировка была использована?

Постарайтесь выяснить это, и если придётся — угадайте. (Не забудьте задокументировать свою догадку с помощью комментария.)

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

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

Можно ли использовать Unicode в моих Perl-источниках?

Да, можно! Если ваши исходные файлы закодированы в UTF-8, вы можете указать это с помощью use utf8 псевдонима.

use utf8;

Это ничего не делает с вашим вводом или выводом. Оно лишь влияет на то, как читаются ваши исходные файлы. Вы можете использовать Unicode в строковых литералах, идентификаторах (но они всё ещё должны быть «символами слова» согласно \w) и даже в пользовательских разделителях.

Data::Dumper не восстанавливает флаг UTF8; он сломан?

Нет, возможности Unicode в Data::Dumper работают правильно. Были жалобы на то, что он должен восстанавливать флаг UTF8, когда данные снова читаются с eval. Однако вам на самом деле не нужно смотреть на флаг, и ничего не указывает на то, что Data::Dumper должен нарушать это правило.

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

Если вы правильно кодируете свои строки для вывода, ни одна из этих проблем вас не касается, и вы можете просто eval выводимые данные, как всегда.

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

Начиная с Perl 5.14 (и частично в Perl 5.12), просто добавьте use feature 'unicode_strings' в начале своей программы. В пределах его лексического пространства вы не должны иметь этой проблемы. Он также автоматически включается при use feature ':5.12' или use v5.12 или с использованием -E в командной строке для Perl 5.12 или выше.

Обоснование в том, чтобы потребовать этого, заключается в том, чтобы не сломать более старые программы, которые полагаются на то, как всё работало до появления Unicode. Эти старые программы знали только о наборе символов ASCII, и поэтому могут не работать должным образом с дополнительными символами. Когда строка закодирована в UTF-8, Perl предполагает, что программа готова работать с Unicode, но когда строка не закодирована, Perl предполагает, что требуется только ASCII, и поэтому эти символы, которые не являются ASCII-символами, не распознаются как то, чем они являются в Unicode. use feature 'unicode_strings' говорит Perl, чтобы он обрабатывал все символы как Unicode, независимо от того, закодирована ли строка в UTF-8 или нет, тем самым избегая проблемы.

Однако в более ранних версиях Perl или если вы передаёте строки подпрограммам за пределами области действия функции, вы можете принудительно применять правила Unicode, изменив кодировку на UTF-8, выполнив utf8::upgrade($string). Это можно безопасно использовать для любой строки, так как оно проверяет и не изменяет строки, которые уже были преобразованы.

Для более подробного обсуждения см. Unicode::Semantics на CPAN.

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

См. ответ на предыдущий вопрос.

Как определить, является ли строка текстовой или двоичной?

Вы не можете. Некоторые используют флаг UTF8 для этого, но это неправильное использование, и это портит хорошо себя ведущие модули, такие как Data::Dumper. Флаг бесполезен для этой цели, потому что он выключен, когда используется кодировка 8 бит (по умолчанию ISO-8859-1) для хранения строки.

Это то, о чем вам, программисту, нужно следить; извините. Вы можете рассмотреть возможность принятия какой-то «венгерской нотации», чтобы помочь в этом.

Как преобразовать кодировку FOO в кодировку BAR?

Сначала преобразуйте строку байтов FOO в строку текста, а затем строку текста в строку байтов BAR:

my $text_string = decode('FOO', $foo_string);
my $bar_string  = encode('BAR', $text_string);

или, пропустив часть строки текста, перейдя непосредственно от одной двоичной кодировки к другой:

use Encode qw(from_to);
from_to($string, 'FOO', 'BAR');  # changes contents of $string

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

open my $foofh, '<:encoding(FOO)', 'example.foo.txt';
open my $barfh, '>:encoding(BAR)', 'example.bar.txt';
print { $barfh } $_ while <$foofh>;

Что такое decode_utf8 и encode_utf8?

Это альтернативные синтаксические конструкции для decode('utf8', ...) и encode('utf8', ...). Не используйте эти функции для обмена данными. Вместо этого используйте decode('UTF-8', ...) и encode('UTF-8', ...); см. "В чем разница между UTF-8 и utf8?" ниже.

Что такое «широкий символ»?

Это термин, используемый для символов, занимающих более одного байта.

Предупреждение Perl «Широкий символ в...» вызывается таким символом. Без указанного уровня кодировки Perl пытается поместить вещи в один байт. Когда он не может, он выводит это предупреждение (если включены предупреждения) и использует данные, закодированные в UTF-8.

Чтобы избежать этого предупреждения и избежать разных кодировок вывода в одном потоке, всегда явно указывайте кодировку, например, с помощью уровня PerlIO:

binmode STDOUT, ":encoding(UTF-8)";

Внутренние данные

Что такое «флаг UTF8»?

Пожалуйста, если вы не занимаетесь модификацией внутренней части или отладкой странностей, вообще не думайте о флаге UTF8. Это означает, что вы очень вероятно не должны использовать is_utf8, _utf8_on или _utf8_off вообще.

Флаг UTF8, также называемый SvUTF8, — это внутренний флаг, указывающий, что текущая внутренняя представление — UTF-8. Без флага предполагается ISO-8859-1. Perl автоматически преобразует между ними. (На самом деле Perl обычно предполагает, что представление — ASCII; см. "Почему классы символов регулярных выражений иногда соответствуют только диапазону ASCII?" выше.)

Один из внутренних форматов Perl — UTF-8. К сожалению, Perl не может хранить секреты, поэтому все знают об этом. Это причина многих путаниц. Лучше притворяться, что внутренний формат — это какая-то неизвестная кодировка, и что вам всегда нужно явно кодировать и декодировать.

Что насчет использования псевдонима use bytes?

Не используйте его. Не имеет смысла иметь дело с байтами в строке текста, и не имеет смысла иметь дело с символами в строке байтов. Произведите правильные преобразования (путем декодирования/кодирования), и все будет хорошо работать: вы получите счетчики символов для декодированных данных и счетчики байтов для закодированных данных.

use bytes обычно является неудачной попыткой сделать что-то полезное. Просто забудьте о нем.

Что насчет использования псевдонима use encoding?

Не используйте его. К сожалению, он предполагает, что среда программиста и пользователя будут использовать одну и ту же кодировку. Он будет использовать одну и ту же кодировку для исходного кода и для STDIN и STDOUT. При копировании программы на другую машину исходный код не меняется, но среда STDIO может измениться.

Если вам нужны символы, не являющиеся ASCII, в исходном коде, сделайте его файлом с кодировкой UTF-8 и use utf8.

Если вам нужно установить кодировку для STDIN, STDOUT и STDERR, например, на основе локалей пользователя, use open.

В чем разница между :encoding и :utf8?

Поскольку UTF-8 — один из внутренних форматов Perl, вы часто можете просто пропустить этап кодирования или декодирования и напрямую манипулировать флагом UTF8.

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

Вместо decode и encode, вы можете использовать _utf8_on и _utf8_off, но это считается плохим стилем. Особенно _utf8_on может быть опасным по той же причине, что и :utf8.

Есть некоторые сокращения для однострочных выражений; см. -C в perlrun.

В чем разница между UTF-8 и utf8?

UTF-8 — это официальный стандарт. utf8 — это способ Perl быть либеральным в том, что он принимает. Если вам нужно взаимодействовать с вещами, которые не так либеральны, вы можете рассмотреть возможность использования UTF-8. Если вам нужно взаимодействовать с вещами, которые слишком либеральны, вам может потребоваться использовать utf8. Полное объяснение находится в "UTF-8 vs. utf8 vs. UTF8" в Encode.

UTF-8 внутренне известно как utf-8-strict. Учебник последовательно использует UTF-8, даже там, где внутренне используется utf8, потому что различие может быть трудным для восприятия и в основном не имеет значения.

Например, utf8 может использоваться для кодовых точек, которые не существуют в Unicode, например, 9999999, но если вы закодируете это в UTF-8, вы получите символ подстановки (по умолчанию; см. "Обработка поврежденных данных" в Encode для других способов работы с этим.)

Хорошо, если вы настаиваете: «внутренний формат» — utf8, а не UTF-8. (Когда это не какая-то другая кодировка.)

Я потерял след; какая кодировка действительно используется во внутреннем формате?

Хорошо, что вы потеряли след, потому что вам не следует полагаться на то, что внутренний формат — какая-то конкретная кодировка. Но раз вы спросили: по умолчанию внутренний формат — либо ISO-8859-1 (latin-1), либо utf8, в зависимости от истории строки. На платформах EBCDIC это может быть по-другому.

Perl знает, как он хранил строку внутри, и будет использовать эти знания, когда вы encode. Другими словами: не пытайтесь определить внутреннюю кодировку для определенной строки, а вместо этого просто закодируйте её в нужную вам кодировку.

Автор

Juerd Waalboer <#####@juerd.nl>

См. также

perlunicode, perluniintro, Encode

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.32.0/perlunifaq

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API