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 обычно выбирает block последовательных незарезервированных кодовых точек для своих символов. До сих пор количество кодовых точек в этих блоках всегда было кратно 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. Эта модель оказалась неверной, или, по крайней мере, неуклюжей: теперь «Unicode» привязан к данным, а не к операциям. Начиная с Perl v5.8.0, существует только один случай, когда необходимо явное use utf8: если ваш скрипт Perl закодирован в UTF-8, вы можете использовать UTF-8 в именах идентификаторов и в строковых и регулярных выражениях, сказав use utf8. Это не является значением по умолчанию, потому что скрипты с устаревшими 8-битными данными в них сломались. См. utf8.
Модель Unicode Perl
Perl поддерживает как строки пре-5.6 с восьмибитными исходными байтами, так и строки с символами Unicode. Общий принцип заключается в том, что Perl старается сохранить свои данные как восьмибитные байты как можно дольше, но как только Unicodeness не может быть избежано, данные прозрачно обновляются до Unicode. До Perl v5.14.0 обновление не было полностью прозрачным (см. "The "Unicode Bug"" in 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, хотя: вы можете увидеть, есть ли он у вас, запустив «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}/; или, начиная с v5.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 v5.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, что является стандартным на большинстве систем.
Отображение Юникода в виде текста
Иногда может потребоваться отобразить переменные Perl, содержащие Юникод, в виде простого текста 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 ACUTELATIN CAPITAL LETTER A?)Короткий ответ заключается в том, что Perl по умолчанию сравнивает равенство (
eq,ne) только на основе кодовых точек символов. В приведенном выше случае ответ — нет (поскольку 0x00C1 != 0x0041). Но иногда все символы А с заглавной буквы должны считаться равными, или даже буквы А любого регистра.Длинный ответ заключается в том, что необходимо учитывать вопросы нормализации символов и регистров: см. 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(и ASCIIaпоfдля шестнадцатеричных). Для получения безопасных преобразований из любой строки Юникода используйте "num()" в Unicode::UCD.
Вопросы с ответами
-
Сломаются ли мои старые скрипты?
Вероятно, нет. Если вы каким-то образом не генерируете символы Юникода, старое поведение должно сохраниться. Единственное поведение, которое изменилось и которое может начать генерировать Юникод, это старое поведение
chr(), где передача аргумента больше 255 давала символ по модулю 255.chr(300), например, равнялосьchr(45)или "-" (в ASCII), теперь это большая латинская буква I с бреве. -
Как заставить мои скрипты работать с Юникодом?
Вероятно, потребуется очень мало работы, так как ничего не изменится, пока вы не сгенерируете данные Юникода. Самое важное — получать входные данные в виде Юникода; для этого см. предыдущую дискуссию об I/O. Для полной бесшовной поддержки Юникода добавьте
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 Дополнительные ресурсы
-
Консорциум Юникода
-
Вопросы и ответы по Юникоду
-
Глоссарий Юникода
-
Рекомендуемый список для чтения Юникода
Консорциум Юникода составил список статей и книг, некоторые из которых дают гораздо более глубокое рассмотрение Юникода: http://unicode.org/resources/readinglist.html
-
Полезные ресурсы по Юникоду
-
Поддержка Юникода и множества языков в HTML, шрифтах, веб-браузерах и других приложениях
-
UTF-8 и часто задаваемые вопросы о Юникоде для Unix/Linux
-
Устаревшие кодовые таблицы
-
Вы можете изучить различную информацию из файлов данных Юникода с помощью модуля
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–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.34.0/perluniintro