Spec-Zone.ru › Perl 5.38

perlunifaq

СОДЕРЖАНИЕ

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

НАЗВАНИЕ

perlunifaq - Часто задаваемые вопросы по Юникоду в Perl

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

В этом списке вопросы и ответы о Юникоде в Perl, предназначенные для чтения после perlunitut.

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

Нет, и это не совсем FAQ по Юникоду.

Perl имеет абстрагированный интерфейс для всех поддерживаемых кодировок символов, поэтому это фактически учебник по <%%CODE_BLOCK_0%%%> общей работе и Encode часто задаваемым вопросам. Но многие люди считают, что Юникод — это нечто особенное и магическое, и я не хотел их разочаровывать, поэтому я решил назвать документ учебником по Юникоду.

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

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

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

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

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

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

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

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

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

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

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

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

Всякий раз, когда ваша закодированная двоичная строка используется вместе со строкой текста, Perl предположит, что ваша двоичная строка была закодирована с помощью ISO-8859-1, также известной как latin-1. Если это не latin-1, ваши данные будут нежелательно преобразованы. Например, если это был UTF-8, отдельные байты многобайтовых символов будут восприниматься как отдельные символы, а затем снова преобразовываться в UTF-8. Такое двойное кодирование можно сравнить с двойным кодированием HTML (&amp;gt;) или двойным кодированием 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.

Что делать, если неизвестна используемая кодировка?

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

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

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

Можно ли использовать Юникод в моих исходных Perl-файлах?

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

use utf8;

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

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

Нет, возможности 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 или более поздних версий.

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

END_OF_DOCUMENT_MARKER

Однако, в более ранних версиях 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–2023 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.38.0/perlunifaq

Spec-Zone.ru

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