Spec-Zone.ru › Perl 5.34

perlunifaq

СОДЕРЖАНИЕ

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

НАЗВАНИЕ

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

Вопросы и ответы

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

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

Нет, и это не совсем часто задаваемые вопросы по Unicode.

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

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

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

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

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

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

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

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

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

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

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

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

Что произойдёт, если не декодировать?

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

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

Что произойдёт, если не кодировать?

Зависит от того, что вы выводите и как.

Вывод через файловый дескриптор

  • Если символы строки имеют код точки 255 или меньше, Perl выводит байты, соответствующие этим кодам. Так происходит с закодированными строками. Это также может произойти с незакодированными строками, если все символы имеют код точки 255 или меньше.

  • В противном случае Perl выводит строку, закодированную в UTF-8. Это происходит только со строками, которые не были закодированы. Поскольку этого не должно происходить, Perl также выводит предупреждение «широкий символ» в этом случае.

Другие механизмы вывода (например, exec, chdir, ..)

Ваша текстовая строка будет отправлена с помощью байтов в внутреннем формате Perl.

Поскольку внутренний формат часто 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 pragmy.

use utf8;

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

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

Нет, возможности Data::Dumper по работе с Unicode работают так, как и должны. Были некоторые жалобы, что он должен восстанавливать флаг 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)";

INTERNALS

Что такое «флаг 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. Другими словами: не пытайтесь выяснить, какая кодировка используется внутри для определённой строки, а вместо этого просто закодируйте её в ту кодировку, которая вам нужна.

AUTHOR

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

См. также

perlunicode, perluniintro, Encode

© 1993–2021 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.34.0/perlunifaq

Spec-Zone.ru

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