Spec-Zone.ru › Perl 5.28

perluniintro

СОДЕРЖАНИЕ

  • ИМЯ
  • ОПИСАНИЕ
    • Unicode
    • Поддержка Unicode в Perl
    • Модель Unicode в Perl
    • Unicode и EBCDIC
    • Создание Unicode
      • Ограничения предыдущих версий
    • Обработка Unicode
    • Зависимые кодировки
    • Ввод-вывод Unicode
    • Отображение Unicode как текста
    • Особые случаи
    • Продвинутые темы
    • Разное
    • Вопросы с ответами
    • Шестнадцатеричная запись
    • Дополнительные ресурсы
  • UNICODE В СТАРЫХ ВЕРСИЯХ PERL
  • СМОТРИТЕ ТАКЖЕ
  • БЛАГОДАРНОСТИ
  • АВТОР, АВТОРСКИЕ ПРАВА И ЛИЦЕНЗИЯ

ИМЯ

perluniintro - Введение в Unicode для Perl

ОПИСАНИЕ

Этот документ предоставляет общее представление об Unicode и о том, как использовать Unicode в Perl. См. "Дополнительные ресурсы" для ссылок на более углубленные исследования Unicode.

Unicode

Unicode — это стандарт набора символов, который планирует закодировать все письменные системы мира, а также многие другие символы.

Unicode и ISO/IEC 10646 — это согласованные стандарты, которые объединяют почти все другие современные стандарты наборов символов, охватывая более 80 письменных систем и сотни языков, включая все коммерчески важные современные языки. Все символы в самых больших китайских, японских и корейских словарях также закодированы. Стандарты в конечном итоге охватят почти все символы в более чем 250 письменных системах и тысячах языков. Unicode 1.0 был выпущен в октябре 1991 года, а 6.0 — в октябре 2010 года.

Unicode-символ — это абстрактный объект. Он не привязан к какой-либо конкретной ширине целого числа, особенно не к языку C char. Unicode не зависит от языка и отображения: он не кодирует язык текста и обычно не определяет шрифты или другие графические детали макета. Unicode работает с символами и с текстом, построенным из этих символов.

Unicode определяет символы, такие как LATIN CAPITAL LETTER A или GREEK SMALL LETTER ALPHA, и уникальные номера для символов, в данном случае 0x0041 и 0x03B1 соответственно. Эти уникальные номера называются кодовыми точками. Кодовая точка в основном является позицией символа в наборе всех возможных символов Unicode, и поэтому в Perl термин порядковый номер часто используется взаимозаменяемо с ним.

Стандарт Unicode предпочитает использовать шестнадцатеричную запись для кодовых точек. Если такие числа, как 0x0041, вам незнакомы, взгляните на последующий раздел "Шестнадцатеричная запись". Стандарт Unicode использует запись U+0041 LATIN CAPITAL LETTER A, чтобы указать шестнадцатеричную кодовую точку и нормативное имя символа.

Unicode также определяет различные свойства символов, такие как «заглавные буквы» или «строчные буквы», «цифра» или «знак препинания»; эти свойства независимы от имен символов. Кроме того, определены различные операции над символами, такие как преобразование в верхний регистр, в нижний регистр и сортировка (сортировка).

Unicode логический «символ» может фактически состоять из более чем одного внутреннего фактического «символа» или кодовой точки. Для западноевропейских языков это адекватно моделируется основным символом (например, LATIN CAPITAL LETTER A) и одним или несколькими модификаторами (например, COMBINING ACUTE ACCENT). Эта последовательность основного символа и модификаторов называется последовательностью объединяемых символов. Некоторые нелатинские языки требуют более сложных моделей, поэтому Unicode создал концепцию кластера графем, которая была позже дополнительно усовершенствована в расширенный кластер графем. Например, слог корейского хангыля считается одним логическим символом, но чаще всего состоит из трех фактических символов Unicode: ведущей согласной, последующей гласной и заключительной согласной.

Следует ли называть эти расширенные кластеры графем «символами», зависит от вашей точки зрения. Если вы программист, то, вероятно, вы склонны рассматривать каждый элемент в последовательностях как единицу или «символ». Однако с точки зрения пользователя вся последовательность может рассматриваться как один «символ», поскольку, скорее всего, именно так это выглядит в контексте языка пользователя. В этом документе мы придерживаемся точки зрения программиста: один «символ» — это одна кодовая точка Unicode.

Для некоторых комбинаций основного символа и модификаторов существуют прекомпонованные символы. Например, существует один эквивалентный символ для последовательности LATIN CAPITAL LETTER A и COMBINING ACUTE ACCENT. Он называется LATIN CAPITAL LETTER A WITH ACUTE. Однако эти прекомпонованные символы доступны только для некоторых комбинаций и предназначены в основном для поддержки двусторонних преобразований между Unicode и старыми стандартами (такими как ISO 8859). Использование последовательностей, как делает Unicode, позволяет использовать меньшее количество основных строительных блоков (кодовых точек) для выражения гораздо большего количества потенциальных кластеров графем. Для поддержки преобразования между эквивалентными формами также определены различные формы нормализации. Таким образом, LATIN CAPITAL LETTER A WITH ACUTE находится в составной форме нормализации (сокращенно NFC), а последовательность LATIN CAPITAL LETTER A и COMBINING ACUTE ACCENT представляют тот же символ в разложенной форме нормализации (NFD).

Из-за обратной совместимости со старыми кодировками идея «уникального числа для каждого символа» немного нарушается: вместо этого существует «по крайней мере одно число для каждого символа». Один и тот же символ может быть представлен по-разному в нескольких старых кодировках. Обратное неверно: некоторые кодовые точки не имеют назначенного символа. Во-первых, существуют незаполненные кодовые точки в иным образом используемых блоках. Во-вторых, существуют специальные управляющие символы Unicode, которые не представляют собой истинных символов.

Когда Unicode был впервые задуман, считалось, что все символы мира могут быть представлены с использованием 16-битного слова; это означает, что необходимо максимум 0x10000 (или 65 536) символов, от 0x0000 до 0xFFFF. Это быстро оказалось неверным, и начиная с Unicode 2.0 (июль 1996 г.), Unicode был определен вплоть до 21 бита (0x10FFFF), а Unicode 3.1 (март 2001 г.) определил первые символы выше 0xFFFF. Первые 0x10000 символов называются плоскостью 0 или Основной многоязычной плоскостью (BMP). С Unicode 3.1 было определено 17 (да, семнадцать) плоскостей, но они еще далеки от заполнения определенными символами.

При кодировании нового языка Unicode обычно выбирает блок последовательных незаполненных кодовых точек для своих символов. До сих пор количество кодовых точек в этих блоках всегда было кратно 16. Излишки в блоке, которые в настоящее время не нужны, остаются незаполненными для будущего роста. Но были случаи, когда в более поздней версии требовалось больше кодовых точек, чем имеющихся излишков, и новый блок необходимо было разместить в другом месте, не смежном с исходным, чтобы справиться с переполнением. Таким образом, стало очевидно на ранней стадии, что «блок» не является адекватной организационной основой, и поэтому было создано свойство Script. (Позже было добавлено и улучшенное свойство сценария — свойство Script_Extensions.) Эти кодовые точки, которые находятся в блоках переполнения, могут все еще иметь тот же сценарий, что и исходные. Концепция сценария лучше согласуется с естественным языком: существует Latin сценарий, Greek сценарий и так далее; и есть несколько искусственных сценариев, таких как Common для символов, используемых в нескольких сценариях, таких как математические символы. Сценарии обычно охватывают различные части нескольких блоков. Более подробную информацию о сценариях см. в "Сценарии" в perlunicode. Разделение на блоки существует, но оно почти полностью случайно — артефакт того, как символы были и по-прежнему распределены. (Обратите внимание, что в этом абзаце вещи упрощены для введения. Unicode на самом деле не кодирует языки, а системы письма для них — их сценарии; и один сценарий может использоваться многими языками. Unicode также кодирует вещи, которые не имеют прямого отношения к языкам, например, такие символы, как BAGGAGE CLAIM.)

Кодовые точки Unicode — это просто абстрактные числа. Для ввода и вывода этих абстрактных чисел эти числа должны быть каким-то образом закодированы или сериализованы. Unicode определяет несколько форм кодирования символов, из которых UTF-8 является наиболее популярной. UTF-8 — это кодировка с переменной длиной, которая кодирует символы Unicode как 1–4 байта. Другие кодировки включают UTF-16 и UTF-32 и их варианты с порядком байтов (UTF-8 независим от порядка байтов). ISO/IEC 10646 определяет формы кодирования UCS-2 и UCS-4.

Для получения дополнительной информации о кодировках — например, чтобы узнать, что такое супплементы и метки порядка байтов (BOM) — см. perlunicode.

Поддержка Unicode в Perl

Начиная с Perl v5.6.0, Perl имеет возможность обрабатывать Unicode в стандартном режиме. Однако Perl v5.8.0 — это первая рекомендуемая версия для серьезной работы с Unicode. Обновление 5.6.1 исправило многие проблемы первоначальной реализации Unicode, но, например, регулярные выражения по-прежнему не работают с Unicode в 5.6.1. Perl v5.14.0 — это первая версия, где поддержка Unicode практически без проблем интегрируется без подводных камней. (Есть несколько исключений. Во-первых, некоторые различия в quotemeta были исправлены, начиная с Perl 5.16.0. Во-вторых, некоторые различия в операторе диапазона были исправлены, начиная с Perl 5.26.0. В-третьих, некоторые различия в split были исправлены, начиная с Perl 5.28.0.)

Для активации этой бесшовной поддержки следует use feature 'unicode_strings' (что автоматически выбирается, если у вас use 5.012 или выше). См. feature. (В версии 5.14 также исправлено множество ошибок и отклонений от стандарта Unicode.)

Перед Perl v5.8.0 использовалось use utf8 для объявления, что операции в текущем блоке или файле будут работать с Unicode. Эта модель оказалась ошибочной, или, по крайней мере, неуклюжей: «уникодовость» теперь передаётся с данными, а не прикрепляется к операциям. Начиная с Perl v5.8.0, остаётся только один случай, когда требуется явное use utf8: если ваш скрипт Perl закодирован в UTF-8, вы можете использовать UTF-8 в именах идентификаторов, а также в строковых и регулярных выражениях, сказав use utf8. Это не является значением по умолчанию, потому что скрипты с устаревшей 8-битной информацией в них сломаются. См. utf8.

Модель Unicode в Perl

Perl поддерживает как строки из восьмибитных исходных байтов версии до 5.6, так и строки из символов Unicode. Общий принцип заключается в том, что Perl пытается сохранить свои данные как восьмибитные байты как можно дольше, но как только уникодовость не может быть избегнута, данные прозрачно обновляются до Unicode. Перед Perl v5.14.0 обновление не было полностью прозрачным (см. "Ошибка Unicode" в perlunicode), и для обратной совместимости полная прозрачность достигается только при выборе use feature 'unicode_strings' (см. feature) или use 5.012 (или выше).

Внутренне Perl в настоящее время использует либо нативный восьмибитный набор символов платформы (например, Latin-1), по умолчанию UTF-8, для кодирования строк Unicode. Конкретно, если все кодовые точки в строке равны или меньше 0xFF, Perl использует нативный восьмибитный набор символов. В противном случае он использует UTF-8.

Пользователю Perl обычно не нужно знать и не нужно заботиться о том, как Perl кодирует свои внутренние строки, но это становится важным при выводе строк Unicode в поток без слоя PerlIO (с кодировкой «по умолчанию»). В таком случае будут использованы исходные байты, используемые внутри (нативный набор символов или UTF-8, соответственно для каждой строки), и будет выведено предупреждение «Широкий символ», если эти строки содержат символ за пределами 0x00FF.

Например,

perl -e 'print "\x{DF}\n", "\x{0100}\x{DF}\n"'

производит довольно бесполезную смесь исходных байтов и UTF-8, а также предупреждение:

Wide character in print at ...

Для вывода UTF-8 используйте слой вывода :encoding или :utf8. Предварительное добавление

binmode(STDOUT, ":utf8");

к этой примерной программе гарантирует, что вывод полностью UTF-8, и удаляет предупреждение программы.

Вы можете включить автоматическое преобразование в UTF-8 ваших стандартных файловых дескрипторов, слой вывода по умолчанию open() и @ARGV, используя либо командную строку -C, либо переменную среды PERL_UNICODE, см. perlrun для документации параметра -C.

Обратите внимание, что это означает, что Perl ожидает, что другое программное обеспечение будет работать таким же образом: если Perl предполагает, что STDIN должен быть UTF-8, но STDIN, поступающий из другой команды, не является UTF-8, Perl, вероятно, пожалуется на неправильный UTF-8.

Все функции, объединяющие Unicode и ввод-вывод, также требуют использования новой функции PerlIO. Однако почти все платформы Perl 5.8 используют PerlIO: вы можете проверить, использует ли ваша платформа PerlIO, выполнив «perl -V» и посмотрев на useperlio=define.

Unicode и EBCDIC

Perl 5.8.0 добавил поддержку Unicode на платформах EBCDIC. Эта поддержка была прекращена в последующих выпусках, но была возрождена в версии 5.22. Поддержка Unicode несколько сложнее для реализации, так как требуются дополнительные преобразования. См. perlebcdic для получения дополнительной информации.

На платформах EBCDIC внутренняя форма кодирования Unicode — UTF-EBCDIC, а не UTF-8. Разница в том, что UTF-8 «безопасен для ASCII» в том, что символы ASCII кодируются в UTF-8 как есть, в то время как UTF-EBCDIC «безопасен для EBCDIC», так как все основные символы (включая все, имеющие эквиваленты ASCII (например, "A", "0", "%", и т. д.) одинаковы как в EBCDIC, так и в UTF-EBCDIC. Часто в документации термин «UTF-8» используется и для обозначения UTF-EBCDIC. Это случай и в этом документе.

Создание Unicode

Этот раздел полностью относится к Perl, начиная с версии 5.22. Различные замечания для более ранних версий находятся в подразделе "Примечания к более ранним версиям" ниже.

Для создания символов Unicode в литералах используйте обозначение \N{...} в строках с двойными кавычками:

my $smiley_from_name = "\N{WHITE SMILING FACE}";
my $smiley_from_code_point = "\N{U+263a}";

Аналогично, они могут быть использованы в литералах регулярных выражений

$smiley =~ /\N{WHITE SMILING FACE}/;
$smiley =~ /\N{U+263a}/;

Во время выполнения вы можете использовать:

use charnames ();
my $hebrew_alef_from_name
                     = charnames::string_vianame("HEBREW LETTER ALEF");
my $hebrew_alef_from_code_point = charnames::string_vianame("U+05D0");

Естественно, ord() выполнит обратное действие: преобразует символ в кодовую точку.

Есть и другие варианты выполнения во время выполнения. Вы можете использовать pack():

my $hebrew_alef_from_code_point = pack("U", 0x05d0);

Или вы можете использовать chr(), хотя в общем случае это менее удобно:

$hebrew_alef_from_code_point = chr(utf8::unicode_to_native(0x05d0));
utf8::upgrade($hebrew_alef_from_code_point);

utf8::unicode_to_native() и utf8::upgrade() не нужны, если аргумент больше 0xFF, поэтому вышеприведенное можно было бы записать как

$hebrew_alef_from_code_point = chr(0x05d0);

поскольку 0x5d0 больше 255.

\x{} и \o{} также могут быть использованы для указания кодовых точек во время компиляции в строках с двойными кавычками, но для обратной совместимости со старыми версиями Perl применяются те же правила, что и для chr() для кодовых точек меньше 256.

utf8::unicode_to_native() используется для того, чтобы код Perl был переносимым на платформы EBCDIC. Вы можете опустить его, если вы действительно уверены, что никто никогда не захочет использовать ваш код на платформе, не поддерживающей ASCII. Начиная с Perl v5.22, вызовы к нему на платформах ASCII оптимизируются, так что добавление его не снижает производительность. Или вы можете просто использовать другие конструкции, которые не требуют этого.

См. "Дополнительные ресурсы", чтобы найти все эти имена и числовые коды.

Примечания к более ранним версиям

На платформах EBCDIC до v5.22 использование \N{U+...} не работает должным образом.

До версии 5.16 использование \N{...} с именем символа (в отличие от кодовой точки U+...) требовало use charnames :full.

До версии 5.14 в \N{...} с именем символа (в отличие от кодовой точки U+...) были некоторые ошибки.

charnames::string_vianame() была добавлена в версии 5.14. До этого charnames::vianame() должна была работать, но только если аргумент имеет вид "U+...". Вариант для получения Unicode во время выполнения по имени символа — скорее всего:

use charnames ();
my $hebrew_alef_from_name
                 = pack("U", charnames::vianame("HEBREW LETTER ALEF"));

Обработка Unicode

Обработка Unicode в большинстве случаев прозрачна: просто используйте строки как обычно. Функции, такие как index(), length() и substr(), будут работать с символами Unicode; регулярные выражения будут работать с символами Unicode (см. perlunicode и perlretut).

Обратите внимание, что Perl рассматривает кластеры графем как отдельные символы, поэтому, например,

print length("\N{LATIN CAPITAL LETTER A}\N{COMBINING ACUTE ACCENT}"),
      "\n";

выведет 2, а не 1. Единственным исключением является то, что регулярные выражения имеют \X для сопоставления расширенного кластера графем. (Таким образом, \X в регулярном выражении будет соответствовать всей последовательности обоих символов примера).

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

Устаревшие кодировки

Когда вы объединяете устаревшие данные и Unicode, устаревшие данные необходимо обновить до Unicode. Обычно предполагается, что устаревшие данные — ISO 8859-1 (или EBCDIC, если применимо).

Модуль Encode знает о многих кодировках и имеет интерфейсы для преобразования между ними:

use Encode 'decode';
$data = decode("iso-8859-3", $data); # convert from legacy

Ввод-вывод Unicode

Обычно вывод данных Unicode

print FH $some_string_with_unicode, "\n";

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

open FH, ">:utf8", "file";

open FH, ">:encoding(ucs2)",      "file";
open FH, ">:encoding(UTF-8)",     "file";
open FH, ">:encoding(shift_jis)", "file";

и для уже открытых потоков используйте binmode():

binmode(STDOUT, ":utf8");

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

Сопоставление имён кодировок является приблизительным: регистр не важен, и многие кодировки имеют несколько псевдонимов. Обратите внимание, что слой :utf8 всегда должен быть указан точно так; он не подлежит приблизительному сопоставлению имён кодировок. Также обратите внимание, что в настоящее время :utf8 небезопасен для ввода, потому что он принимает данные без проверки того, является ли это действительно допустимым UTF-8; вместо этого вы должны использовать :encoding(UTF-8) (с или без дефиса).

См. PerlIO для слоя :utf8, PerlIO::encoding и Encode::PerlIO для слоя :encoding(), и Encode::Supported для многих кодировок, поддерживаемых модулем Encode.

Чтение файла, который, как вы знаете, закодирован в одной из кодировок Unicode или устаревших кодировок, не превращает данные в Unicode в глазах Perl. Для этого укажите соответствующий слой при открытии файлов

open(my $fh,'<:encoding(UTF-8)', 'anything');
my $line_of_unicode = <$fh>;

open(my $fh,'<:encoding(Big5)', 'anything');
my $line_of_unicode = <$fh>;

Слой ввода-вывода также можно указать более гибко с помощью прагмы open. См. open, или посмотрите следующий пример.

use open ':encoding(UTF-8)'; # input/output default encoding will be
                             # UTF-8
open X, ">file";
print X chr(0x100), "\n";
close X;
open Y, "<file";
printf "%#x\n", ord(<Y>); # this should print 0x100
close Y;

С прагмой open вы можете использовать слой :locale

BEGIN { $ENV{LC_ALL} = $ENV{LANG} = 'ru_RU.KOI8-R' }
# the :locale will probe the locale environment variables like
# LC_ALL
use open OUT => ':locale'; # russki parusski
open(O, ">koi8");
print O chr(0x430); # Unicode CYRILLIC SMALL LETTER A = KOI8-R 0xc1
close O;
open(I, "<koi8");
printf "%#x\n", ord(<I>), "\n"; # this should print 0xc1
close I;

Эти методы устанавливают прозрачный фильтр на потоке ввода-вывода, который преобразует данные из указанной кодировки при чтении из потока. Результат всегда Unicode.

Прагма open влияет на все вызовы open() после прагмы, устанавливая слои по умолчанию. Если вы хотите повлиять только на определённые потоки, используйте явные слои непосредственно в вызове open().

Вы можете переключаться между кодировками в уже открытом потоке, используя binmode(); см. "binmode" в perlfunc.

:locale в настоящее время не работает с open() и binmode(), только с прагмой open. Методы :utf8 и :encoding(...) работают со всеми open(), binmode() и прагмой open.

Аналогично, вы можете использовать эти слои ввода-вывода для выходных потоков, чтобы автоматически преобразовать Unicode в указанную кодировку при записи в поток. Например, следующий фрагмент копирует содержимое файла «text.jis» (закодированного как ISO-2022-JP, т. е. JIS) в файл «text.utf8», закодированный как UTF-8:

open(my $nihongo, '<:encoding(iso-2022-jp)', 'text.jis');
open(my $unicode, '>:utf8',                  'text.utf8');
while (<$nihongo>) { print $unicode $_ }

Имена кодировок, как с прагмой open(), так и с прагмой open, позволяют использовать гибкие имена: koi8-r и KOI8R будут поняты.

Общие кодировки, признаваемые ISO, MIME, IANA и различными другими организациями по стандартизации, распознаются; для более подробного списка см. Encode::Supported.

read() считывает символы и возвращает количество символов. seek() и tell() работают с количеством байтов, как и sysseek().

sysread() и syswrite() не следует использовать с файловыми дескрипторами, имеющими уровни кодировки символов, они ведут себя плохо, и такое поведение устарело с perl 5.24.

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

# BAD CODE WARNING
open F, "file";
local $/; ## read in the whole file of 8-bit characters
$t = <F>;
close F;
open F, ">:encoding(UTF-8)", "file";
print F $t; ## convert to UTF-8 on output
close F;

Если вы запустите этот код дважды, содержимое файла file будет закодировано в UTF-8 дважды. Использование use open ':encoding(UTF-8)' позволило бы избежать ошибки, или явное открытие файла file для ввода как UTF-8.

ПРИМЕЧАНИЕ: возможности :utf8 и :encoding работают только если ваш Perl был скомпилирован с PerlIO, что является значением по умолчанию на большинстве систем.

Отображение Unicode как текста

Иногда вам может потребоваться отобразить Perl-скаляры, содержащие Unicode, как обычный ASCII (или EBCDIC) текст. Следующая подпрограмма преобразует свой аргумент таким образом, чтобы символы Unicode с кодовыми точками больше 255 отображались как \x{...}, управляющие символы (например, \n) отображались как \x.., а остальные символы отображались как есть:

sub nice_string {
       join("",
       map { $_ > 255                    # if wide character...
             ? sprintf("\\x{%04X}", $_)  # \x{...}
             : chr($_) =~ /[[:cntrl:]]/  # else if control character...
               ? sprintf("\\x%02X", $_)  # \x..
               : quotemeta(chr($_))      # else quoted or as themselves
       } unpack("W*", $_[0]));           # unpack Unicode characters
  }

Например,

nice_string("foo\x{100}bar\n")

возвращает строку

'foo\x{0100}bar\x0A'

которая готова к печати.

(\\x{} используется здесь вместо \\N{}, так как, скорее всего, вы хотите увидеть исходные значения.)

Особые случаи

  • Начиная с Perl 5.28, битовые операторы, такие как ~, не могут использоваться со строками, содержащими кодовые точки выше 255.

  • Функция vec() может давать неожиданные результаты, если используется со строками, содержащими символы с порядковыми значениями выше 255. В таком случае результаты согласуются с внутренней кодировкой символов, но не с чем-то ещё. Поэтому этого не следует делать, и начиная с Perl 5.28, при этом выдаётся сообщение об устаревании, а начиная с Perl 5.32, это действие становится недопустимым.

  • Просмотр внутренней кодировки Perl

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

    Один способ взглянуть на внутреннюю кодировку символов Unicode — использовать unpack("C*", ... для получения байтов той кодировки, которую использует строка, или unpack("U0..", ...) для получения байтов UTF-8 кодировки:

    # this prints  c4 80  for the UTF-8 bytes 0xc4 0x80
    print join(" ", unpack("U0(H2)*", pack("U", 0x100))), "\n";

    Ещё один способ — использовать модуль Devel::Peek:

    perl -MDevel::Peek -e 'Dump(chr(0x100))'

    Это показывает флаг UTF8 в FLAGS, а также байты UTF-8 и символы Unicode в PV. См. также обсуждение функции utf8::is_utf8() позже в этом документе.

Дополнительные темы

  • Равенство строк

    Вопрос равенства строк становится несколько сложным в Unicode: что вы имеете в виду под «равенством»?

    (Равна ли LATIN CAPITAL LETTER A WITH ACUTE LATIN CAPITAL LETTER A?)

    Короткий ответ заключается в том, что Perl по умолчанию сравнивает эквивалентность (eq, ne) только на основе кодовых точек символов. В приведенном выше случае ответ — нет (потому что 0x00C1 != 0x0041). Но иногда все символы A с заглавной буквы должны считаться равными или даже все A независимо от регистра.

    Длинный ответ заключается в том, что вам необходимо учитывать нормализацию символов и вопросы регистра: см. Unicode::Normalize, Технический отчет Unicode #15, Формы нормализации Unicode и разделы по отображению регистра в Стандарте Unicode.

    Начиная с Perl 5.8.0, реализовано «полное» преобразование в нижний регистр (Case Mappings/SpecialCasing), но остаются ошибки в qr//i при их использовании, в основном исправленные в версии 5.14 и практически полностью в 5.18.

  • Сортировка строк

    Людям нравится сортировать строки — или, как говорят в Unicode, сортировать их. Но что вы имеете в виду под сортировкой?

    (Предшествует ли LATIN CAPITAL LETTER A WITH ACUTE или следует за LATIN CAPITAL LETTER A WITH GRAVE?)

    Короткий ответ состоит в том, что Perl по умолчанию сравнивает строки (lt, le, cmp, ge, gt ) только на основе кодовых точек символов. В данном случае ответ — «следует», так как 0x00C1 > 0x00C0.

    Длинный ответ состоит в том, что «это зависит», и нельзя дать хороший ответ без знания (как минимум) контекста языка. См. Unicode::Collate и Алгоритм сортировки Unicode http://www.unicode.org/unicode/reports/tr10/

Разное

  • Диапазоны символов и классы

    Диапазоны символов в квадратных скобках в регулярных выражениях (например, /[a-z]/) и в операторе tr/// (также известном как y///) не обладают волшебными возможностями Unicode. Это означает, что [A-Za-z] не начнет волшебным образом означать «все буквы»; (не то чтобы это означало и для 8-битных символов; для них, если вы используете локальные наборы (perllocale), используйте /[[:alpha:]]/; а если нет, используйте 8-битный оператор \p{alpha}).

    Все свойства, начинающиеся с \p (и его обратного значения \P ) на самом деле являются классами символов, которые учитывают Unicode. Их десятки, см. perluniprops.

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

    qr/ [ \N{U+03} - \N{U+20} ] /xx

    включает кодовые точки \N{U+03}, \N{U+04}, ..., \N{U+20}.

    Это также работает для диапазонов в tr/// начиная с Perl v5.24.

  • Преобразования строк в числа

    Unicode определяет несколько других десятичных и числовых символов помимо знакомых 0–9, таких как арабские и индийские цифры. Perl не поддерживает преобразование строк в числа для цифр, кроме ASCII 0–9 (и ASCII a–f для шестнадцатеричных). Для получения безопасных преобразований из любой строки Unicode используйте "num()" в Unicode::UCD.

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

  • Сломаются ли мои старые скрипты?

    Вероятнее всего, нет. Если вы каким-то образом не генерируете символы Юникода, старое поведение должно сохраниться. Практически единственное измененное поведение, которое может начать генерировать Юникод, — это старое поведение chr(), где передача аргумента больше 255 производила символ по модулю 255. chr(300), например, был равен chr(45) или «-» (в ASCII), теперь это заглавная буква I с диэрезом.

  • Как сделать мои скрипты совместимыми с Юникодом?

    Потребуется очень мало усилий, поскольку ничего не меняется, пока вы не генерируете данные Юникода. Самое важное — получать ввод в формате Юникода; об этом см. предыдущее обсуждение ввода/вывода. Для полной бесшовной поддержки Юникода добавьте use feature 'unicode_strings' (или use 5.012 или более позднюю версию) в свой скрипт.

  • Как узнать, является ли моя строка строкой Юникода?

    Вам не нужно об этом беспокоиться. Но это может потребоваться, если ваш Perl имеет версию ниже 5.14.0 или вы не указали use feature 'unicode_strings' или use 5.012 (или более позднюю версию), поскольку в противном случае правила для кодовых точек в диапазоне от 128 до 255 отличаются в зависимости от того, является ли содержащая их строка строкой Юникода или нет. (См. "Когда Юникод не используется" в perlunicode.)

    Чтобы определить, является ли строка строкой Юникода, используйте:

    print utf8::is_utf8($string) ? 1 : 0, "\n";

    Но обратите внимание, что это не означает, что какие-либо символы в строке обязательно закодированы в UTF-8 или что какие-либо символы имеют кодовые точки больше 0xFF (255) или даже 0x80 (128), или что в строке вообще есть какие-либо символы. Все, что делает is_utf8(), — это возвращает значение внутреннего флага «utf8ness», прикрепленного к $string. Если флаг выключен, байты в скаляре интерпретируются как кодировка с одним байтом. Если флаг включен, байты в скаляре интерпретируются как (переменной длины, потенциально многобайтовые) кодовые точки, закодированные в UTF-8, символов. Байты, добавленные в строку, закодированную в UTF-8, автоматически преобразуются в UTF-8. Если объединены смешанные скаляры, не закодированные в UTF-8 и закодированные в UTF-8 (интерполяция в двойных кавычках, явное конкатенация или подстановка параметра printf/sprintf), результат будет закодирован в UTF-8, как если бы копии байтовых строк были преобразованы в UTF-8: например,

    $a = "ab\x80c";
    $b = "\x{100}";
    print "$a = $b\n";

    выходная строка будет закодирована в UTF-8 ab\x80c = \x{100}\n, но $a останется закодированной в байтах.

    Иногда вам может потребоваться узнать длину строки в байтах, а не в символах. Для этого используйте препроцессор bytes и функцию length().

    my $unicode = chr(0x100);
    print length($unicode), "\n"; # will print 1
    use bytes;
    print length($unicode), "\n"; # will print 2
                                  # (the 0xC4 0x80 of the UTF-8)
    no bytes;
  • Как узнать кодировку файла?

    Вы можете попробовать Encode::Guess, но у него есть ряд ограничений.

  • Как определить данные, которые не являются допустимыми в определенной кодировке?

    Используйте пакет Encode, чтобы попытаться преобразовать их. Например,

    use Encode 'decode';
    
    if (eval { decode('UTF-8', $string, Encode::FB_CROAK); 1 }) {
        # $string is valid UTF-8
    } else {
        # $string is not valid UTF-8
    }

    Или используйте unpack, чтобы попытаться декодировать их:

    use warnings;
    @chars = unpack("C0U*", $string_of_bytes_that_I_think_is_utf8);

    Если данные недопустимы, генерируется предупреждение Malformed UTF-8 character. «C0» означает «обрабатывать строку символ за символом». Без этого unpack("U*", ...) будет работать в режиме U0 (по умолчанию, если строка формата начинается с U ), и она вернет байты, составляющие UTF-8 кодировку целевой строки, что всегда будет работать.

  • Как преобразовать двоичные данные в определенную кодировку или наоборот?

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

    В некотором смысле то, о чем вы спрашиваете, не имеет большого смысла: кодировки предназначены для символов, а двоичные данные — это не «символы», поэтому преобразование «данных» в какую-либо кодировку не имеет смысла, если вы не знаете, в какой кодовой таблице и кодировке находятся двоичные данные, в противном случае это больше не просто двоичные данные.

    Если у вас есть последовательность байтов, которые, как известно, должны интерпретироваться с помощью определенной кодировки, вы можете использовать Encode.

    use Encode 'from_to';
    from_to($data, "iso-8859-1", "UTF-8"); # from latin-1 to UTF-8

    Вызов from_to() изменяет байты в $data, но в отношении природы строки в Perl ничего существенного не изменилось. Как до, так и после вызова строка $data содержит только набор 8-битных байтов. Что касается Perl, кодировка строки остается «система-родными 8-битными байтами».

    Вы можете связать это с вымышленным модулем 'Translate':

    use Translate;
    my $phrase = "Yes";
    Translate::from_to($phrase, 'english', 'deutsch');
    ## phrase now contains "Ja"

    Содержимое строки изменяется, но не ее природа. Perl ничего не знает после вызова о том, что содержимое строки указывает на утверждение.

    Вернемся к преобразованию данных. Если у вас есть (или нужны) данные в родной 8-битной кодировке вашей системы (например, Latin-1, EBCDIC и т. д.), вы можете использовать pack/unpack для преобразования в/из Юникода.

    $native_string  = pack("W*", unpack("U*", $Unicode_string));
    $Unicode_string = pack("U*", unpack("W*", $native_string));

    Если у вас есть последовательность байтов, которые, как вы знаете, являются допустимыми UTF-8, но Perl этого еще не знает, вы можете убедить Perl в этом тоже:

    $Unicode = $bytes;
    utf8::decode($Unicode);

    или:

    $Unicode = pack("U0a*", $bytes);

    Вы можете найти байты, составляющие последовательность UTF-8 с помощью

    @bytes = unpack("C*", $Unicode_string)

    и вы можете создать правильно сформированные данные Юникода с помощью

    $Unicode_string = pack("U*", 0xff, ...)
  • Как отображать Юникод? Как вводить Юникод?

    См. http://www.alanwood.net/unicode/ и http://www.cl.cam.ac.uk/~mgk25/unicode.html

  • Как Юникод взаимодействует с традиционными локалями?

    Если ваша локаль — это UTF-8 локаль, начиная с Perl v5.26, Perl хорошо работает со всеми категориями; до этого, начиная с Perl v5.20, он работает со всеми категориями, кроме LC_COLLATE, которая связана с сортировкой и оператором cmp. Обратите внимание, что стандартные модули Unicode::Collate и Unicode::Collate::Locale предлагают гораздо более мощные решения проблем сортировки и работают на более ранних версиях.

    Для других локалей, начиная с Perl 5.16, вы можете указать

    use locale ':not_characters';

    чтобы Perl хорошо взаимодействовал с ними. Сложность заключается в том, что вам самим нужно преобразовывать данные из локальной кодовой таблицы в Юникод и обратно. См. "Unicode ввод/вывод" выше, как это

    use open ':locale';

    для этого, но полные подробности см. в "Unicode и UTF-8" в perllocale, включая уловки, которые происходят, если вы не указали :not_characters.

Шестнадцатеричная нотация

Стандарт Юникода предпочитает использовать шестнадцатеричную нотацию, так как она более наглядно показывает разделение Юникода на блоки из 256 символов. Шестнадцатеричная форма также короче десятичной. Вы можете использовать десятичную нотацию, но освоение шестнадцатеричной нотации упрощает работу со стандартом Юникода. Например, запись U+HHHH использует шестнадцатеричную нотацию.

Префикс 0x означает шестнадцатеричное число, цифры составляют 0-9 и a-f (или A-F, регистр не важен). Каждая шестнадцатеричная цифра представляет четыре бита или половину байта. print 0x..., "\n" отобразит шестнадцатеричное число в десятичном виде, а printf "%x\n", $decimal отобразит десятичное число в шестнадцатеричном. Если у вас есть только «шестнадцатеричные цифры» шестнадцатеричного числа, вы можете использовать функцию hex().

print 0x0009, "\n";    # 9
print 0x000a, "\n";    # 10
print 0x000f, "\n";    # 15
print 0x0010, "\n";    # 16
print 0x0011, "\n";    # 17
print 0x0100, "\n";    # 256

print 0x0041, "\n";    # 65

printf "%x\n",  65;    # 41
printf "%#x\n", 65;    # 0x41

print hex("41"), "\n"; # 65

Дополнительные ресурсы

  • Консорциум Юникода

    http://www.unicode.org/

  • Вопросы и ответы по Юникоду

    http://www.unicode.org/unicode/faq/

  • Словарь Юникода

    http://www.unicode.org/glossary/

  • Рекомендованный список для чтения по Юникоду

    Консорциум Юникода имеет список статей и книг, некоторые из которых дают более глубокое изучение Юникода: http://unicode.org/resources/readinglist.html

  • Полезные ресурсы по Юникоду

    http://www.unicode.org/unicode/onlinedat/resources.html

  • Поддержка Юникода в HTML, шрифтах, веб-браузерах и других приложениях

    http://www.alanwood.net/unicode/

  • Вопросы и ответы по UTF-8 и Юникоду для Unix/Linux

    http://www.cl.cam.ac.uk/~mgk25/unicode.html

  • Кодовые таблицы старого образца

    http://www.czyborra.com/ http://www.eki.ee/letter/

  • Вы можете изучить различные данные из файлов данных Юникода, используя модуль Unicode::UCD.

ЮНИКОД В СТАРЫХ PERLS

Если вы не можете обновить Perl до версии 5.8.0 или выше, вы по-прежнему можете выполнить некоторые операции с Юникодом, используя модули Unicode::String, Unicode::Map8, и Unicode::Map, доступные из CPAN. Если у вас установлен GNU recode, вы также можете использовать Perl-интерфейс Convert::Recode для преобразования символов.

Ниже приведены быстрые преобразования из байтов ISO 8859-1 (Latin-1) в байты UTF-8 и обратно. Код работает даже с более старыми версиями Perl 5.

# ISO 8859-1 to UTF-8
s/([\x80-\xFF])/chr(0xC0|ord($1)>>6).chr(0x80|ord($1)&0x3F)/eg;

# UTF-8 to ISO 8859-1
s/([\xC2\xC3])([\x80-\xBF])/chr(ord($1)<<6&0xC0|ord($2)&0x3F)/eg;

СМОТРИТЕ ТАКЖЕ

perlunitut, perlunicode, Encode, open, utf8, bytes, perlretut, perlrun, Unicode::Collate, Unicode::Normalize, Unicode::UCD

БЛАГОДАРНОСТИ

Спасибо любезным читателям рассылок perl5-porters@perl.org, perl-unicode@perl.org, linux-utf8@nl.linux.org и unicore@unicode.org за ценные отзывы.

АВТОР, АВТОРСКИЕ ПРАВА И ЛИЦЕНЗИЯ

Авторские права 2001-2011 Jarkko Hietaniemi <jhi@iki.fi>. В настоящее время поддерживается Perl 5 Porters.

Данный документ может быть распространен на тех же условиях, что и сам Perl.

© 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.28.3/perluniintro

Spec-Zone.ru

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