perlunifaq
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- В. И О.
- perlunitut — это не учебник по Unicode, не так ли?
- Какие кодировки символов поддерживает Perl?
- Какую версию Perl следует использовать?
- Что насчёт двоичных данных, таких как изображения?
- Когда следует декодировать или кодировать?
- Что произойдёт, если я не декодирую?
- Что произойдёт, если я не закодирую?
- Есть ли способ автоматически декодировать или кодировать?
- Что делать, если я не знаю, какая кодировка была использована?
- Можно ли использовать Unicode в моих исходных кодах Perl?
- Data::Dumper не восстанавливает флаг UTF8; он сломан?
- Почему классы символов в регулярных выражениях иногда соответствуют только диапазону ASCII?
- Почему некоторые символы не преобразуются в верхний или нижний регистр корректно?
- Как определить, является ли строка текстовой строкой или двоичной строкой?
- Как преобразовать кодировку FOO в кодировку BAR?
- Что такое decode_utf8 и encode_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. Если это не 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 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–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.30.3/perlunifaq