perlunifaq
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- Вопросы и ответы
- perlunitut — это не совсем учебник по Юникоду, не так ли?
- Какие кодировки символов поддерживает Perl?
- Какую версию Perl следует использовать?
- Что делать с двоичными данными, такими как изображения?
- Когда следует декодировать или кодировать?
- Что делать, если я не декодирую?
- Что делать, если я не кодирую?
- Можно ли автоматически декодировать или кодировать?
- Что делать, если я не знаю, какая кодировка была использована?
- Можно ли использовать Юникод в моих Perl-источниках?
- Data::Dumper не восстанавливает флаг UTF8; он сломан?
- Почему классы символов в регулярных выражениях иногда соответствуют только диапазону ASCII?
- Почему некоторые символы не преобразуются в верхний или нижний регистр должным образом?
- Как определить, является ли строка текстовой строкой или двоичной строкой?
- Как преобразовать кодировку FOO в кодировку BAR?
- Что такое decode_utf8 и encode_utf8?
- Что такое «широкий символ»?
- ВНУТРЕННЕЕ УСТРОЙСТВО
- АВТОР
- СМОТРИТЕ ТАКЖЕ
НАЗВАНИЕ
perlunifaq - Часто задаваемые вопросы по Юникоду в Perl
Вопросы и ответы
Это список вопросов и ответов по Юникоду в Perl, предназначенный для чтения после perlunitut.
perlunitut — это не совсем учебник по Юникоду, не так ли?
Нет, и это не совсем часто задаваемые вопросы по Юникоду.
Perl имеет абстрагированный интерфейс для всех поддерживаемых кодировок символов, поэтому это фактически общий Encode учебник и Encode часто задаваемые вопросы. Но многие люди думают, что Юникод — это нечто особенное и магическое, и я не хотел их разочаровывать, поэтому я решил назвать документ учебником по Юникоду.
Какие кодировки символов поддерживает Perl?
Чтобы узнать, какие кодировки символов поддерживает ваш Perl, выполните:
perl -MEncode -le "print for Encode->encodings(':all')" Какую версию Perl следует использовать?
Хорошо, если вы можете, обновитесь до последней версии, но обязательно 5.8.1 или более поздней. В учебнике и часто задаваемых вопросах предполагается последняя версия.
Вы также должны проверить свои модули и обновить их при необходимости. Например, HTML::Entities требует версию >= 1.32 для правильной работы, даже несмотря на то, что changelog об этом умалчивает.
Что делать с двоичными данными, такими как изображения?
Ну, помимо чистого binmode $fh, вы не должны их специально обрабатывать. (Псевдоним binmode нужен, потому что иначе Perl может преобразовывать окончания строк на системах Win32.)
Однако будьте осторожны, чтобы никогда не объединять текстовые строки с двоичными строками. Если вам нужен текст в двоичном потоке, сначала закодируйте ваши текстовые строки с помощью соответствующей кодировки, затем объедините их с двоичными строками. См. также: «Что делать, если я не кодирую?».
Когда следует декодировать или кодировать?
Всякий раз, когда вы передаете текст чему-либо внешнему по отношению к вашему процессу Perl, например, базе данных, текстовому файлу, сокету или другой программе. Даже если то, с чем вы общаетесь, также написано на Perl.
Что делать, если я не декодирую?
Всякий раз, когда ваша закодированная двоичная строка используется вместе с текстовой строкой, Perl предположит, что ваша двоичная строка была закодирована с помощью ISO-8859-1, также известной как latin-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.
Что делать, если я не знаю, какая кодировка была использована?
Сделайте все возможное, чтобы выяснить это, и если нужно — угадайте. (Не забудьте задокументировать свою догадку с помощью комментария.)
Вы можете открыть документ в веб-браузере и изменить набор символов или кодировку символов, пока не убедитесь визуально, что все символы отображаются должным образом.
Нет надежного способа автоматического определения кодировки, поэтому, если люди продолжают отправлять вам данные без указания кодировки, вам может потребоваться обучить их.
Можно ли использовать Юникод в моих 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 или нет, тем самым устраняя проблему.
Однако, в более ранних версиях 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.36.0/perlunifaq