Spec-Zone.ru › Perl 5.32

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

Модель Unicode Perl

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

Внутри Perl в настоящее время используется либо нативный 8-битный характерный набор платформы (например, Latin-1), по умолчанию UTF-8, для кодирования строк Unicode. В частности, если все коды символов в строке меньше или равны 0xFF, Perl использует нативный 8-битный набор символов. В противном случае он использует 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: вы можете узнать, используется ли она на вашей платформе, запустив «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}/;

или, начиная с версии 5.32:

$smiley =~ /\p{Name=WHITE SMILING FACE}/;
$smiley =~ /\p{Name=whitesmilingface}/;

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

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 версии 5.22, вызовы к нему на платформах ASCII оптимизируются, поэтому добавление его не влечёт за собой никаких затрат на производительность. Или вы можете просто использовать другие конструкции, не требующие его.

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

Замечания о предыдущих выпусках

На платформах EBCDIC до версии 5.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 pragma, позволяет использовать гибкие имена: 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, что является стандартным на большинстве систем.

Отображение Юникода в виде текста

Иногда может потребоваться отобразить перловые скаляры, содержащие Юникод, в виде простого текста ASCII (или EBCDIC). Следующая подпрограмма преобразует свой аргумент таким образом, что символы Юникода с кодовыми точками больше 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 кодирует ту или иную строку Юникода (потому что стандартные способы получения содержимого строки с Юникодом — через ввод и вывод — всегда должны использовать явно определенные слои ввода/вывода). Но если вам нужно, есть два способа посмотреть за кулисы.

    Один способ узнать внутреннюю кодировку символов Юникода — использовать 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, так и символы Юникода в PV. См. также обсуждение функции utf8::is_utf8() в этой документации.

Продвинутые темы

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

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

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

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

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

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

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

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

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

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

    Подробный ответ: «зависит», и точного ответа невозможно дать без знания (как минимум) контекста языка. См. Unicode::Collate и алгоритм сортировки Юникода https://www.unicode.org/unicode/reports/tr10/

Разное

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

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

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

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

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

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

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

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

    Юникод определяет несколько других десятичных и числовых символов помимо знакомых 0–9, таких как арабские и индийские цифры. Perl не поддерживает преобразование строк в числа для цифр, отличных от ASCII 0 по 9 (и ASCII a по f для шестнадцатеричных). Для безопасного преобразования из любой строки Юникода используйте "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 ничего больше не знает после вызова, чем до него, о том, что содержимое строки указывает на утверждение.

    Вернёмся к преобразованию данных. Если у вас есть (или вы хотите иметь) данные в кодировке вашего компьютера (например, 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 хорошо с ними взаимодействовал. Загвоздка в том, что вам нужно самостоятельно переводить из кодировки локали в Юникод и наоборот. См. "Ввод-вывод Юникода" выше, как

    use open ':locale';

    чтобы сделать это, но полные подробности находятся в "Юникод и 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

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

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

    https://www.unicode.org/

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

    https://www.unicode.org/unicode/faq/

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

    https://www.unicode.org/glossary/

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

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

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

    https://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.

ЮНИКОД В СТАРЫХ ВЕРСИЯХ PERL

Если вы не можете обновить 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.32.0/perluniintro

Spec-Zone.ru

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