perlunicode
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
- Важные замечания
- Семантика байтов и символов
- Правила ASCII против правил Unicode
- Расширенные кластеры графем (логические символы)
- Свойства символов Unicode
- Сравнение \N{...} и \p{name=...}
- Подстановочные знаки в значениях свойств
- Пользовательские свойства символов
- Пользовательские сопоставления регистров (только для серьёзных хакеров)
- Кодировки символов для ввода и вывода
- Уровень поддержки Unicode для регулярных выражений
- Кодировки Unicode
- Несимвольные кодовые точки
- За пределами кодовых точек Unicode
- Последствия использования Unicode для безопасности
- Unicode в Perl на EBCDIC
- Локали
- Когда Unicode не используется
- «Ошибка Unicode»
- Принуждение к использованию Unicode в Perl (или отказ от Unicode в Perl)
- Использование Unicode в XS
- Модификация Perl для работы с более ранними версиями Unicode (только для очень серьёзных хакеров)
- Перевод кода из perl-5.6.X
- ОШИБКИ
- СМОТРИ ТАКЖЕ
НАЗВАНИЕ
perlunicode - Поддержка Unicode в Perl
ОПИСАНИЕ
Если вы ещё не знакомы, перед чтением этого документа, вы должны ознакомиться с perlunitut и perluniintro.
Unicode стремится ОБЪЕДИНИТЬ кодировки всех систем символов мира в единый стандарт. Для многих стандартов кодирования, существовавших до создания Unicode, преобразование из них в Unicode по сути означало добавление константы к каждой кодовой точке в оригинальном стандарте, а преобразование обратно — просто вычитание той же константы. Для ASCII и ISO-8859-1 константа равна 0. Для ISO-8859-5 (кириллица) константа равна 864; для иврита (ISO-8859-8) — 1488; тайского (ISO-8859-11) — 3424 и так далее. Это упростило преобразования и способствовало принятию Unicode.
И это сработало; в наши дни эти устаревшие стандарты редко используются. Большинство людей используют Unicode.
Unicode — это комплексный стандарт. Он определяет много аспектов, выходящих за рамки Perl, таких как отображение последовательностей символов. Для подробного обсуждения всех аспектов Unicode см. https://www.unicode.org.
Важные замечания
Хотя некоторые части этого раздела могут быть неясны при первом чтении, мы считаем важным выделить некоторые подводные камни перед дальнейшим изучением, поэтому вот:
Поддержка Unicode — это обширное требование. Хотя Perl не реализует стандарт Unicode или сопутствующие технические отчеты от начала до конца, Perl поддерживает многие функции Unicode.
Кроме того, использование Unicode может создать проблемы безопасности, которые не очевидны, см. «Последствия использования Unicode для безопасности» ниже.
-
Наиболее безопасно, если вы
use feature 'unicode_strings' -
Для сохранения обратной совместимости Perl не включает полную внутреннюю поддержку Unicode, если не указана директива
use feature 'unicode_strings'. (Это автоматически выбирается, если выuse v5.12или выше.) Невыполнение этого может вызвать неожиданные сюрпризы. См. «Ошибка Unicode» ниже.Эта директива не влияет на ввод/вывод. Она также не изменяет внутреннее представление строк, а только их интерпретацию. Есть несколько мест, где Unicode не поддерживается полностью, например, в именах файлов.
- Слои ввода и вывода
-
Используйте
:encoding(...)слой для чтения из и записи в файловые дескрипторы с использованием указанной кодировки. (См. open.) - Вы должны перевести свои скрипты Perl, не использующие ASCII и UTF-8, в UTF-8.
-
Модуль encoding устарел с perl 5.18, а внутренние механизмы Perl, которые он использует, были удалены с perl 5.26.
-
use utf8всё ещё необходимо для включения UTF-8 в скриптах -
Если ваш скрипт Perl закодирован в UTF-8, директива
use utf8должна быть явно включена, чтобы обеспечить распознавание этой кодировки (в строковых или регулярных выражениях или в именах идентификаторов). Это единственный случай, когда нужна явная директиваuse utf8. (См. utf8).Если скрипт Perl начинается с байтов, которые формируют кодировку UTF-8 Unicode BYTE ORDER MARK (
BOM, см. «Кодировки Unicode»), эти байты полностью игнорируются. - Скрипты UTF-16 автоматически распознаются
-
Если скрипт Perl начинается с Unicode
BOM(UTF-16LE, UTF16-BE), или если скрипт выглядит как UTF-16 без метки порядка байтов любого порядка, Perl правильно прочитает скрипт как соответствующую кодировку Unicode.
Семантика байтов и символов
До Unicode большинство кодировок использовали 8 бит (один байт) для кодирования каждого символа. Таким образом, символ был байтом, а байт был символом, и могло быть только 256 или меньше возможных символов. «Семантика байтов» в заголовке этого раздела относится к этому поведению. Не было необходимости различать «Байт» и «Символ».
Затем появляется Unicode, у которого есть место для более миллиона символов (и Perl позволяет ещё больше). Это означает, что для представления символа может потребоваться более одного байта, и поэтому эти два термина больше не эквивалентны. Важны символы как целые сущности, а не обычно байты, которые их составляют. Именно это подразумевает термин «Семантика символов» в заголовке этого раздела.
Perl пришлось изменить внутреннее представление, чтобы отделить «байты» от «символов». Важно, чтобы и вы изменили своё представление, если вы этого ещё не сделали, чтобы «байт» и «символ» больше не означали одно и то же в вашем сознании.
Базовым строительным блоком строк Perl всегда был «символ». Изменения в основном сводятся к тому, что реализация больше не считает, что символ всегда представляет собой один байт.
Необходимо отметить несколько вещей:
-
Функции обработки строк по большей части продолжают работать с символами.
length(), например, возвращает количество символов в строке, как и раньше. Но это количество больше не обязательно совпадает с количеством байтов в строке (байтов может быть больше, чем символов). Другие такие функции включаютchop(),chomp(),substr(),pos(),index(),rindex(),sort(),sprintf(), иwrite().Исключениями являются:
-
побитовые
vec -
байтовые
pack/unpack"C"форматыОднако спецификатор
Wработает с целыми символами, как и спецификаторU. -
некоторые операторы, взаимодействующие с операционной системой платформы
Примеры — операторы, работающие с именами файлов.
-
когда функции вызываются из области действия директивы
use bytesВероятно, вам следует использовать это только для отладки.
-
-
Строки — включая ключи хешей — и шаблоны регулярных выражений могут содержать символы с порядковыми значениями больше 255.
Если вы используете редактор Unicode для редактирования вашей программы, символы Unicode могут встречаться непосредственно внутри строковых литералов в кодировке UTF-8 или UTF-16. (В первом случае требуется
use utf8, во втором — возможно,BOM.)"Создание Unicode" в perluniintro предоставляет другие способы размещения символов, не входящих в ASCII, в ваших строках.
-
Функции
chr()иord()работают с целыми символами. -
Регулярные выражения соответствуют целым символам. Например,
"."соответствует целому символу, а не только одному байту. -
Оператор
tr///преобразует целые символы. (Обратите внимание, что функциональностьtr///CUбыла удалена. Для аналогичной функциональности см.pack('U0', ...)иpack('C0', ...)). -
scalar reverse()выполняет обращение по символам, а не по байтам. -
Операторы битовых строк,
& | ^ ~и (начав с v5.22)&. |. ^. ~., могут работать с битовыми строками, закодированными в UTF-8, но это может привести к неожиданным результатам, если какие-либо строки содержат кодовые точки выше 0xFF. Начиная с v5.28, наличие такого операнда является фатальной ошибкой. В противном случае операция выполняется над копии операнда, не закодированной в UTF-8. Если вы не уверены в кодировке строки, понизьте её уровень до UTF-8, прежде чем использовать любой из этих операторов; вы можете использоватьutf8::utf8_downgrade().
В итоге, Perl всегда придерживался «семантики символов», но с появлением Unicode это отличается от «семантики байтов».
Правила ASCII по сравнению с правилами Unicode
До Unicode, когда символ был байтом, Perl знал только о 128 символах, определённых в ASCII, с кодовыми точками от 0 до 127 (за исключением случаев под use locale). Это оставило кодовые точки от 128 до 255 незанятыми и доступными для любого использования программой. Единственная семантика, которую они имеют, — это их порядковые номера, и то, что они не входят ни в один из неотрицательных классов символов. Ни один из них не считается соответствующим \w, но все они соответствуют \W.
Конечно, Unicode присваивает каждой из этих кодовых точек определённое значение (вместе с теми, которые выше 255). Чтобы сохранить обратную совместимость, Perl использует значения Unicode только тогда, когда есть указание на то, что предполагается использовать Unicode; в противном случае не-ASCII кодовые точки остаются обработанными так, как если бы они были неназначенными.
Вот способы, которыми Perl узнаёт, что строка должна обрабатываться как Unicode:
-
В области действия
use utf8Если вся программа — Unicode (означается использованием 8-битного Unicode Tрансформационного Fормата), то все строковые литералы в ней должны быть Unicode.
-
В области действия
use feature 'unicode_strings'Эта директива была создана для того, чтобы вы могли явно указать Perl, что операции, выполняемые в её области, должны использовать правила Unicode. В более новых версиях Perl затрагивается больше операций. См. "Ошибка Unicode".
-
В области действия
use v5.12или вышеЭто неявно включает
use feature 'unicode_strings'. -
В области действия
use locale 'not_characters', илиuse locale, и текущая локаль — UTF-8.Первый случай определён как подразумевающий обработку Unicode; второй указывает на локаль Unicode, следовательно, интерпретацию всех строк в ней как Unicode.
-
Когда строка содержит только Unicode кодовую точку
Perl никогда не принимал кодовые точки выше 255 без их Unicode, поэтому их использование подразумевает Unicode для всей строки.
-
Когда строка содержит именованную кодовую точку Unicode
\N{...}Конструкция
\N{...}явно относится к кодовой точке Unicode, даже если она также присутствует в ASCII. Поэтому строка, содержащая её, должна быть Unicode. -
Когда строка получена из внешнего источника, отмеченного как Unicode
Команда
-Cможет указывать, что некоторые входные данные программы являются Unicode, и значения этого могут быть прочитаны вашей Perl-программой, см. "${^UNICODE}" в perlvar. -
Когда строка была повышена до UTF-8
Функция
utf8::utf8_upgrade()может быть явно использована, чтобы постоянно (пока не будет вызван последующийutf8::utf8_downgrade()) рассматривать строку как Unicode. -
Существуют дополнительные методы для шаблонов регулярных выражений
Шаблон, скомпилированный с модификаторами
/uили/a, рассматривается как Unicode (хотя есть некоторые ограничения с/a). При модификаторах/dи/lесть несколько других признаков Unicode; см. "Модификаторы набора символов" в perlre.
Обратите внимание, что всё вышеперечисленное переопределяется в области действия use bytes; но вы должны использовать эту директиву только для отладки.
Также обратите внимание, что некоторые взаимодействия с операционной системой платформы никогда не используют правила Unicode.
Когда правила Unicode действуют:
-
Операторы преобразования регистра используют таблицы преобразования регистра Unicode.
Обратите внимание, что
uc(), или\Uв интерполированных строках, преобразует в верхний регистр, аucfirst, или\uв интерполированных строках, преобразует в заглавный регистр в языках, которые делают это различие (что эквивалентно верхнему регистру в языках без такого разграничения).Существует модуль CPAN,
Unicode::Casing, который позволяет вам определять свои собственные отображения, которые будут использоваться вlc(),lcfirst(),uc(),ucfirst(), иfc(или их строковые вставки в двойных кавычках, такие как\U). (До Perl 5.16 эта функциональность частично предоставлялась в ядре Perl, но страдала от ряда непреодолимых недостатков, поэтому вместо этого был написан модуль CPAN.) -
Классы символов в регулярных выражениях соответствуют свойствам символов, указанным в базе данных свойств Unicode.
\wможет быть использован для соответствия японскому идеографу, например; а[[:digit:]]— бенгальской цифре. -
Именованные свойства, скрипты и диапазоны блоков Unicode могут быть использованы (как скобочные классы символов), используя конструкцию
\p{}«соответствие свойству» и отрицание\P{}, «не соответствует свойству».См. "Свойства символов Unicode" для получения дополнительной информации.
Вы можете определить свои собственные свойства символов и использовать их в регулярном выражении с помощью конструкции
\p{}или\P{}. См. "Пользовательские свойства символов" для получения дополнительной информации.
Расширенные кластеры графем (логические символы)
Рассмотрим символ, например H. Он может появляться с различными знаками вокруг него, такими как острый акцент, или циркумфлекс, или различные крючки, круги, стрелки и т.д. над, под, по сторонам и т.д. Существует много возможностей среди языков мира. Количество комбинаций огромно, и если бы существовал символ для каждой комбинации, скоро исчерпался бы миллионный запас Unicode. Поэтому Unicode выбрал другой подход: есть символ для базового H, и символ для каждого из возможных знаков, и они могут быть по-разному объединены для получения конечного логического символа. Таким образом, логический символ — то, что выглядит как один символ — может быть последовательностью более одного отдельного символа. Стандарт Unicode называет их «расширенными кластерами графем» (что является улучшенной версией практически не используемого «кластера графем»); Perl предоставляет конструкцию \X регулярных выражений для соответствия таким последовательностям в их полном объёме.
Но цель Unicode — объединить существующие стандарты и практики набора символов, и несколько существующих стандартов имеют одиночные символы, которые означают то же, что и некоторые из этих комбинаций, например ISO-8859-1, в котором есть немало таких.
Например, "LATIN CAPITAL LETTER E WITH ACUTE" уже был в этом стандарте, когда появился Unicode. Поэтому Unicode добавил его в свой репертуар как один символ. Но этот символ рассматривается Unicode как эквивалентный последовательности, состоящей из символа "LATIN CAPITAL LETTER E" и символа "COMBINING ACUTE ACCENT".
"LATIN CAPITAL LETTER E WITH ACUTE" называется «прекомпонованным» символом, а его эквивалентность последовательности «E» и «КОМБИНИРУЮЩИЙ АКЦЕНТ» называется каноническим эквивалентом. У всех прекомпонованных символов есть разложение (в эквивалентную последовательность), и тип разложения также называется каноническим. Строка может быть составлена в наибольшей степени из прекомпонованных символов, или она может быть составлена целиком из разложенных символов. Unicode называет это соответственно «Нормальной формой составленной» (NFC) и «Нормальной формой разложенной». Модуль Unicode::Normalize содержит функции, которые преобразуют между двумя этими формами. Строка также может иметь как прекомпонованные, так и разложенные символы; этот модуль можно использовать, чтобы сделать всё одним или другим.
Вам могут быть представлены строки в любой из этих эквивалентных форм. В настоящее время в Perl 5 нет ничего, что игнорировало бы различия. Поэтому вам придётся специально их обработать. Обычно рекомендуется преобразовать ваши входные данные в NFD перед дальнейшей обработкой.
Для получения более подробной информации см. http://unicode.org/reports/tr15/.
Свойства Unicode символов
(Единственный случай, когда Perl рассматривает последовательность отдельных кодовых точек как единый логический символ, — это конструкция \X, уже упомянутая выше. Поэтому в этом обсуждении под «символом» понимается одна кодовая точка Unicode.)
Практически все свойства символов Unicode доступны через регулярные выражения, используя конструкцию \p{} «соответствие свойству» и \P{} «не соответствует свойству» для его отрицания.
Например, \p{Uppercase} соответствует любому одиночному символу с свойством Unicode "Uppercase", тогда как \p{L} соответствует любому символу со свойством General_Category "L" (буква) (см. ниже "General_Category"). Скобки не требуются для имён свойств, состоящих из одной буквы, поэтому \p{L} эквивалентно \pL.
Более формально, \p{Uppercase} соответствует любому одиночному символу, значение свойства Unicode Uppercase которого равно True, и \P{Uppercase} соответствует любому символу, значение свойства Uppercase которого равно False, и они могли бы быть записаны как \p{Uppercase=True} и \p{Uppercase=False} соответственно.
Эта формальность необходима, когда свойства не являются бинарными; то есть, если они могут принимать больше значений, чем просто True и False. Например, свойство Bidi_Class (см. ниже "Типы символов для двунаправленной записи"), может принимать несколько различных значений, таких как Left, Right, Whitespace, и другие. Чтобы сопоставить их, необходимо указать и имя свойства (Bidi_Class), и значение, с которым оно сопоставляется (Left, Right, и т.д.). Это делается, как в примерах выше, путём разделения двух компонентов знаком равенства (или взаимозаменяемо, двоеточием), как \p{Bidi_Class: Left}.
Все определённые Unicode свойства символов могут быть записаны в этих составных формах \p{property=value} или \p{property:value}, но Perl предоставляет некоторые дополнительные свойства, которые записываются только в единственной форме, а также сокращённые формы для всех бинарных свойств и некоторых других, описанных ниже, в которых можно опустить имя свойства и разделитель равенства или двоеточие.
У большинства свойств Unicode символов есть как минимум два синонима (или псевдонимы, если хотите): короткий, более лёгкий для набора, и более длинный, более описательный, и поэтому более лёгкий для понимания. Таким образом, свойства "L" и "Letter" выше эквивалентны и могут быть использованы взаимозаменяемо. Аналогично, "Upper" является синонимом для "Uppercase", и мы могли бы эквивалентно записать \p{Uppercase} как \p{Upper}. Также обычно существует несколько синонимов для значений, которые может принимать свойство. Для бинарных свойств "True" имеет 3 синонима: "T", "Yes", и "Y"; а "False" имеет соответствующие "F", "No", и "N" соответственно. Но будьте осторожны. Короткая форма значения для одного свойства может не означать то же самое, что короткая форма, написанная одинаково для другого. Таким образом, для свойства "General_Category" "L" означает "Letter", но для свойства Bidi_Class "L" означает "Left". Полный список свойств и синонимов находится в perluniprops.
Различия в регистре в именах и значениях свойств не имеют значения; таким образом \p{Upper} означает то же самое, что и \p{upper} или даже \p{UpPeR}. Аналогично, можно добавлять или удалять символы нижнего подчеркивания в любом месте слова, так что они также эквивалентны \p{U_p_p_e_r}. А пробелы, как правило, не имеют значения рядом с небуквенными символами, такими как фигурные скобки и знаки равенства или двоеточия, поэтому \p{ Upper } и \p{ Upper_case : Y } эквивалентны этим значениям. На самом деле, пробелы и даже дефисы обычно могут быть добавлены или удалены в любом месте. Таким образом, даже \p{ Up-per case = Yes} эквивалентен. Всё это называется «свободным соответствием» в Unicode. Свойство «имя» имеет некоторые ограничения в этом отношении из-за нескольких исключительных имен. Полные подробности приведены в https://www.unicode.org/reports/tr44/tr44-24.html#UAX44-LM2.
Несколько мест, где используется более строгое соответствие, — это середина чисел, свойство «имя» и свойства расширения Perl, которые начинаются или заканчиваются подчёркиванием. Более строгое соответствие учитывает пробелы (кроме тех, которые находятся рядом с небуквенными символами), дефисы и не внутренние подчёркивания.
Также можно использовать отрицание в \p{} и \P{} путём вставки символа возведения в степень (^) между первой фигурной скобкой и именем свойства: \p{^Tamil} равно \P{Tamil}.
Практически все свойства устойчивы к сопоставлению без учёта регистра. То есть, добавление модификатора регулярного выражения /i не изменяет то, что они сопоставляют. Есть две группы, которые затронуты. Первая группа — Uppercase_Letter, Lowercase_Letter, и Titlecase_Letter, все из которых соответствуют Cased_Letter при соответствии без учёта регистра /i. А вторая группа — Uppercase, Lowercase, и Titlecase, все из которых соответствуют Cased при соответствии без учёта регистра /i. Эта группа также включает свои подмножества PosixUpper и PosixLower, оба из которых при /i сопоставляют PosixAlpha. (Разница между этими группами заключается в том, что некоторые вещи, такие как римские цифры, встречаются как в верхнем, так и в нижнем регистре, поэтому они Cased, но не считаются буквами, поэтому они не являются Cased_Letter.)
См. "За пределами кодовых точек Unicode" для особых замечаний при сопоставлении свойств Unicode с кодовыми точками, не являющимися Unicode.
Общая категория
Каждый символ Unicode назначен общей категории, которая является «наиболее распространённой категоризацией символа» (из https://www.unicode.org/reports/tr44).
Составной способ записи таких свойств — \p{General_Category=Number} (короткая форма: \p{gc:n}). Но Perl предоставляет сокращения, в которых всё до знака равенства или двоеточия опущено. Поэтому можно вместо этого написать \pN.
Вот короткие и длинные формы значений, которые может принимать свойство General Category:
Short Long
L Letter
LC, L& Cased_Letter (that is: [\p{Ll}\p{Lu}\p{Lt}])
Lu Uppercase_Letter
Ll Lowercase_Letter
Lt Titlecase_Letter
Lm Modifier_Letter
Lo Other_Letter
M Mark
Mn Nonspacing_Mark
Mc Spacing_Mark
Me Enclosing_Mark
N Number
Nd Decimal_Number (also Digit)
Nl Letter_Number
No Other_Number
P Punctuation (also Punct)
Pc Connector_Punctuation
Pd Dash_Punctuation
Ps Open_Punctuation
Pe Close_Punctuation
Pi Initial_Punctuation
(may behave like Ps or Pe depending on usage)
Pf Final_Punctuation
(may behave like Ps or Pe depending on usage)
Po Other_Punctuation
S Symbol
Sm Math_Symbol
Sc Currency_Symbol
Sk Modifier_Symbol
So Other_Symbol
Z Separator
Zs Space_Separator
Zl Line_Separator
Zp Paragraph_Separator
C Other
Cc Control (also Cntrl)
Cf Format
Cs Surrogate
Co Private_Use
Cn Unassigned Свойства, состоящие из одной буквы, соответствуют всем символам в любых подсвойствах из двух букв, начинающихся с той же буквы. LC и L& являются специальными: оба являются псевдонимами множества, состоящего из всего, что соответствует Ll, Lu, и Lt.
Типы символов для двунаправленной записи
Поскольку системы письма различаются по направлению записи (например, иврит и арабский пишутся справа налево), Unicode предоставляет свойство Bidi_Class. Некоторые из значений, которые может принимать это свойство, — это:
Value Meaning
L Left-to-Right
LRE Left-to-Right Embedding
LRO Left-to-Right Override
R Right-to-Left
AL Arabic Letter
RLE Right-to-Left Embedding
RLO Right-to-Left Override
PDF Pop Directional Format
EN European Number
ES European Separator
ET European Terminator
AN Arabic Number
CS Common Separator
NSM Non-Spacing Mark
BN Boundary Neutral
B Paragraph Separator
S Segment Separator
WS Whitespace
ON Other Neutrals Это свойство всегда записывается в составной форме. Например, \p{Bidi_Class:R} соответствует символам, которые обычно пишутся справа налево. В отличие от свойства "General_Category", это свойство может иметь дополнительные значения, которые могут быть добавлены в будущем выпуске Unicode. Перечисленные выше значения составляли полный набор для многих выпусков Unicode, но другие были добавлены в Unicode 6.3; вы всегда можете найти текущий набор в perluniprops. И https://www.unicode.org/reports/tr9/ описывает, как их использовать.
Системы письма
Языки мира записываются множеством различных систем письма. Это предложение (если вы не читаете его в переводе) написано латинским письмом, русский — кириллицей, а греческий — ну, греческим; японский в основном хираганой или катаканой. Есть и многие другие.
Свойства Unicode Script и Script_Extensions показывают, в какой системе письма находится заданный символ. Свойство Script_Extensions — это улучшенная версия Script, как показано ниже. Любое из этих свойств можно указать в составной форме, например, \p{Script=Hebrew} (короткая форма: \p{sc=hebr}), или \p{Script_Extensions=Javanese} (короткая форма: \p{scx=java}). Кроме того, Perl предоставляет сокращения для всех имён свойств Script_Extensions. Можно опустить всё до знака равенства (или двоеточия) и просто написать \p{Latin} или \P{Cyrillic}. (Это не относится к Script, которое должно быть записано в составной форме. До Perl v5.26 одиночная форма возвращала просто Script версию, но была изменена, потому что Script_Extensions даёт лучшие результаты.)
Разница между этими двумя свойствами связана с символами, которые используются в нескольких системах письма. Например, цифры от '0' до '9' используются во многих частях мира. Они помещены в систему письма с именем Common. Другие символы используются всего в нескольких системах письма. Например, "KATAKANA-HIRAGANA DOUBLE HYPHEN" используется как в японских системах письма, катакана, так и в хирагана, но нигде больше. Свойство Script помещает все символы, используемые в нескольких системах письма, в систему письма Common, а свойство Script_Extensions помещает символы, используемые только в нескольких системах письма, в каждую из этих систем; при этом всё ещё используя Common для символов, используемых во многих системах письма. Таким образом, оба соответствуют:
"0" =~ /\p{sc=Common}/ # Matches
"0" =~ /\p{scx=Common}/ # Matches и только первое из них соответствует:
"\N{KATAKANA-HIRAGANA DOUBLE HYPHEN}" =~ /\p{sc=Common} # Matches
"\N{KATAKANA-HIRAGANA DOUBLE HYPHEN}" =~ /\p{scx=Common} # No match И только последние два из них соответствуют:
"\N{KATAKANA-HIRAGANA DOUBLE HYPHEN}" =~ /\p{sc=Hiragana} # No match
"\N{KATAKANA-HIRAGANA DOUBLE HYPHEN}" =~ /\p{sc=Katakana} # No match
"\N{KATAKANA-HIRAGANA DOUBLE HYPHEN}" =~ /\p{scx=Hiragana} # Matches
"\N{KATAKANA-HIRAGANA DOUBLE HYPHEN}" =~ /\p{scx=Katakana} # Matches Script_Extensions — это, таким образом, улучшенная версия Script, в которой меньше символов в системе письма Common, и соответственно больше в других системах письма. Это нововведение в версии Unicode 6.0, и его данные, вероятно, значительно изменятся в последующих выпусках, по мере того, как будут улажены вопросы. Новый код, вероятно, должен использовать Script_Extensions, а не просто Script. Если вы скомпилируете Perl с выпуском Unicode, в котором нет Script_Extensions, то расширения Perl в одиночной форме будут вместо этого ссылаться на обычное свойство Script. Если вы скомпилируете с версией Unicode, в которой нет свойства Script, эти расширения вообще не будут определены.
(На самом деле, помимо Common, система письма Inherited содержит символы, которые используются в нескольких системах письма. Это модификационные символы, которые наследуют значение системы письма управляющего символа. Некоторые из них используются во многих системах письма, и поэтому попадают в Inherited как в Script, так и в Script_Extensions. Другие используются только в нескольких системах письма, поэтому попадают в Inherited в Script, но не в Script_Extensions.)
Стоит подчеркнуть, что в Unicode есть несколько различных наборов цифр, эквивалентных 0-9 и сопоставляемых с \d в регулярном выражении. Если они используются только в одном языке, они находятся в Script и Script_Extensions этого языка. Если они используются более чем в одной системе письма, они будут находиться в sc=Common, но только если они используются во многих системах письма, они должны находиться в scx=Common.
В приведенном выше объяснении опущено несколько деталей; см. UAX#24 «Свойство скрипта Юникода»: https://www.unicode.org/reports/tr24.
Полный список скриптов и их сокращений находится в perluniprops.
Использование префикса "Is"
Для обеспечения обратной совместимости (с древними Perl 5.6) все свойства, которые можно записать без использования составной формы, упомянутой до сих пор, могут иметь префикс Is или Is_, таким образом, \P{Is_Lu}, например, равно \P{Lu}, а \p{IsScript:Arabic} равно \p{Arabic}.
Блоки
Помимо скриптов, Юникод также определяет блоки символов. Разница между скриптами и блоками заключается в том, что понятие скрипта ближе к естественным языкам, а понятие блока больше относится к искусственной группировке, основанной на группах символов Юникода с последовательными порядковыми значениями. Например, блок "Basic Latin" содержит все символы, порядковые значения которых находятся в диапазоне от 0 до 127 включительно; другими словами, символы ASCII. Скрипт "Latin" содержит некоторые буквы из этого, а также несколько других блоков, таких как "Latin-1 Supplement", "Latin Extended-A", и т. д., но не содержит всех символов из этих блоков. Например, он не содержит цифр от 0 до 9, потому что эти цифры используются во многих скриптах, и поэтому находятся в скрипте Common.
Дополнительную информацию о скриптах и блоках см. в UAX#24 «Свойство скрипта Юникода»: https://www.unicode.org/reports/tr24
Свойства Script_Extensions или Script, скорее всего, будут теми, которые вы хотите использовать при обработке естественного языка; свойство Block может иногда быть полезным при работе с основными элементами Юникода.
Имена блоков сопоставляются в составной форме, например, \p{Block: Arrows} или \p{Blk=Hebrew}. В отличие от большинства других свойств, лишь у нескольких имён блоков есть определённое в Юникоде короткое имя.
Perl также определяет синонимы в виде единственного слова для свойства блока в тех случаях, когда это не создаёт конфликтов с чем-либо ещё. Но не используйте ни один из них, потому что они нестабильны. Поскольку это расширения Perl, они подчиняются официальным именам свойств Юникода; Юникод не знает и не заботится о расширениях Perl. Может случиться так, что имя, которое в настоящее время обозначает расширение Perl, в будущем будет без предупреждения изменено на другое свойство Юникода в будущей версии интерпретатора Perl, использующего более позднюю версию Юникода, и ваш код больше не будет работать. Расширения упомянуты здесь для полноты: возьмите имя блока и добавьте один из префиксов: In (например, \p{Blk=Arrows} можно в настоящее время записать как \p{In_Arrows}); или иногда Is (как \p{Is_Arrows}); или иногда вообще без префикса (\p{Arrows}). На момент написания (Юникод 9.0) нет конфликтов при использовании префикса In_, но есть множество конфликтов с другими двумя формами. Например, \p{Is_Hebrew} и \p{Hebrew} означают \p{Script_Extensions=Hebrew}, что НЕ то же самое, что \p{Blk=Hebrew}. Предыдущее руководство состояло в использовании префикса In_ в качестве способа указания блока. Но Юникод 8.0 добавил свойства, имена которых начинаются с In, и теперь ясно, что только удача до сих пор предотвращала конфликты. Использование In лишь незначительно меньше, чем Blk:, и значение последнего понятнее, и гарантировано не будет конфликтовать. Так что не рискуйте. Для нового кода используйте \p{Blk=foo}. И убедитесь, что блок — это то, что вы действительно хотите сделать. В большинстве случаев вместо этого вам нужны скрипты.
Полный список блоков находится в perluniprops.
Другие свойства
Существует гораздо больше свойств, чем простые, описанные здесь. Полный список находится в perluniprops.
Юникод определяет все свои свойства в составной форме, поэтому все свойства в единственной форме являются расширениями Perl. Большинство из них просто синонимы для свойств Юникода, но некоторые являются подлинными расширениями, включая несколько в составной форме. И немало из них на самом деле рекомендуются Юникодом (в https://www.unicode.org/reports/tr18).
Этот раздел содержит подробности обо всех расширениях, которые не являются просто синонимами свойств Юникода в составной форме (для этих свойств вам нужно обратиться к стандарту Юникода.
-
\p{All} -
Это соответствует каждому возможному кодовому знаку. Оно эквивалентно
qr/./s. В отличие от всех других сопоставлений свойств, не определенных пользователем\p{}, если это свойство сопоставляется с кодовым значением, не являющимся Unicode, никогда не генерируется предупреждение (см. "За пределами кодовых значений Unicode" ниже). -
\p{Alnum} -
Это соответствует любому
\p{Alphabetic}или\p{Decimal_Number}символу. -
\p{Any} -
Это соответствует любому из 1_114_112 кодовых значений Unicode. Это синоним для
\p{Unicode}. -
\p{ASCII} -
Это соответствует любому из 128 символов набора символов US-ASCII, который является подмножеством Unicode.
-
\p{Assigned} -
Это соответствует любому присвоенному кодовому значению; то есть любому кодовому значению, общая категория которого не
Unassigned(или, что эквивалентно, неCn). -
\p{Blank} -
Это то же самое, что
\hи\p{HorizSpace}: символ, изменяющий горизонтальную расстановку. -
\p{Decomposition_Type: Non_Canonical}(Short:\p{Dt=NonCanon}) -
Соответствует символу, имеющему любой из типов разложения, не являющихся каноническими. Канонические разложения вводятся в разделе "Расширенные кластеры графем (логические символы)" выше. Однако многие другие символы имеют другой тип разложения, обобщенно называемый «совместимыми» или «неканоническими» разложениями. Последовательности, образующие эти разложения, не считаются канонически эквивалентными преобразованному символу. Примером является
"SUPERSCRIPT ONE". Он несколько похож на обычную цифру 1, но не совсем; его разложение на цифру 1 называется «совместимым» разложением, конкретно «надстрочным» (для «надстрочного») разложением. Есть несколько таких совместимых разложений (см. https://www.unicode.org/reports/tr44).\p{Dt: Non_Canon}— это расширение Perl, которое использует только одно имя для обозначения объединения всех этих разложений.У большинства символов Unicode нет разложения, поэтому тип их разложения —
"None". Следовательно,Non_Canonicalэквивалентноqr/(?[ \P{DT=Canonical} - \p{DT=None} ])/(Обратите внимание, что одно из неканонических разложений называется «совместимость», что, возможно, было бы лучше назвать «разное». Оно включает только те вещи, для которых Unicode не смог придумать более подходящего общего названия.)
-
\p{Graph} -
Соответствует любому графическому символу. Теоретически это означает символ, который на принтере заставит чернила использоваться.
-
\p{HorizSpace} -
Это то же самое, что
\hи\p{Blank}: символ, изменяющий горизонтальную расстановку. -
\p{In=*} -
Это синоним для
\p{Present_In=*} -
\p{PerlSpace} -
Это то же самое, что
\s, ограниченное ASCII, а именно[ \f\n\r\t]и, начиная с Perl v5.18, вертикальная табуляция.Мнемоника: пробел Perl (исходный)
-
\p{PerlWord} -
Это то же самое, что
\w, ограниченное ASCII, а именно[A-Za-z0-9_]Мнемоника: слово Perl (исходное)
-
\p{Posix...} -
Есть несколько таких, которые являются эквивалентами, использующими
\p{}обозначение, для классов Posix и описаны в "Классы символов POSIX" в perlrecharclass. -
\p{Present_In: *}(Short:\p{In=*}) -
Это свойство используется, когда вам нужно знать, в какой версии Unicode присутствует символ.
«*» выше обозначает номер версии Unicode, например,
1.1или12.0, или «*» может также бытьUnassigned. Это свойство будет соответствовать кодовым точкам, окончательное определение которых было установлено на момент выпуска Unicode, указанного номером версии;\p{Present_In: Unassigned}будут соответствовать тем кодовым точкам, значение которых еще предстоит назначить.Например,
U+0041"LATIN CAPITAL LETTER A"присутствовало в самом первом доступном выпуске Unicode, которым является1.1, поэтому это свойство верно для всех действительных версий «*». С другой стороны,U+1EFFбыло назначено только в версии 5.1, когда оно стало"LATIN SMALL LETTER Y WITH LOOP", поэтому единственными «*», которые будут соответствовать ему, являются 5.1, 5.2 и более поздние.Unicode предоставляет свойство
Age, от которого это происходит. Проблема с Age в том, что строгое толкование (которое принимает Perl) указывает на точный выпуск, в котором определяется значение кодового пункта. Таким образом,U+0041будет соответствовать только 1.1; иU+1EFFтолько 5.1. Это обычно не то, что нужно.В некоторых не-Perl реализациях свойства Age значение может быть изменено, чтобы совпадать со значением свойства Perl
Present_In; просто имейте в виду это.Еще одна путаница с обоими этими свойствами заключается в том, что определение не состоит в том, что кодовый пункт был присвоен, а в том, что значение кодового пункта было определено. Это потому, что 66 кодовых точек всегда будут неназначенными, и поэтому
Ageдля них — это версия Unicode, в которой было принято решение сделать их таковыми. Например,U+FDD0должен быть постоянно неназначен символу, и решение об этом было принято в версии 3.1, поэтому\p{Age=3.1}соответствует этому символу, как и\p{Present_In: 3.1}и выше. -
\p{Print} -
Соответствует любому графическому или пробельному символу, за исключением управляющих символов.
-
\p{SpacePerl} -
Это то же самое, что
\s, включая символы, выходящие за пределы ASCII.Мнемоника: Пробел, измененный Perl. (Он не включает вертикальную табуляцию до v5.18, которую и стандарт Posix, и Unicode считают пробелом.)
-
\p{Title}и\p{Titlecase} -
При сопоставлении, учитывающем регистр, оба они соответствуют тем же кодовым точкам, что и
\p{General Category=Titlecase_Letter}(\p{gc=lt}). Разница заключается в том, что при сопоставлении без учета регистра/iэти соответствуют тем же, что и\p{Cased}, тогда как\p{gc=lt}соответствует\p{Cased_Letter. -
\p{Unicode} -
Это соответствует любому из 1_114_112 кодовых значений Unicode.
\p{Any}. -
\p{VertSpace} -
Это то же самое, что
\v: символ, изменяющий вертикальную расстановку. -
\p{Word} -
Это то же самое, что
\w, включая более 100_000 символов, выходящих за пределы ASCII. -
\p{XPosix...} -
Есть несколько таких, которые являются стандартными классами Posix, расширенными до полного диапазона Unicode. Они описаны в "Классы символов POSIX" в perlrecharclass.
Сравнение \N{...} и \p{name=...}
Начиная с Perl 5.32, вы можете указать символ по его имени в шаблонах регулярных выражений, используя \p{name=...}. Это дополняет давно существующий метод использования \N{...}. В следующем кратко излагаются различия между этими двумя методами:
\N{...} \p{Name=...}
can interpolate only with eval yes [1]
custom names yes no [2]
name aliases yes yes [3]
named sequences yes yes [4]
name value parsing exact Unicode loose [5] - [1]
-
Возможность интерполяции означает, что вы можете сделать что-то вроде
qr/\p{na=latin capital letter $which}/и указать
$whichв другом месте. - [2]
-
Вы можете создавать свои собственные имена для символов и перезаписывать официальные имена при использовании
\N{...}. См. "CUSTOM ALIASES" в charnames. - [3]
-
У некоторых символов есть несколько имен (синонимов).
- [4]
-
Некоторым конкретным последовательностям символов дается одно имя, помимо их индивидуальных имен.
- [5]
-
Точное соответствие имен означает, что вы должны точно указывать регистр, дефисы, подчеркивания и пробелы в имени, которое вам нужно. Слабое соответствие следует правилам Unicode https://www.unicode.org/reports/tr44/tr44-24.html#UAX44-LM2, где эти элементы в основном несущественны. За исключением нескольких выпадающих символов, эти правила такие же, как и для любого другого свойства
\p{...}.
Подстановочные знаки в значениях свойств
Начиная с Perl 5.30, возможно сделать что-то вроде этого:
qr!\p{numeric_value=/\A[0-5]\z/}! или, сократив и добавив /x,
qr! \p{nv= /(?x) \A [0-5] \z / }! Это соответствует всем кодовым точкам, числовое значение которых равно одному из 0, 1, 2, 3, 4 или 5. Этот конкретный пример мог бы быть написан как
qr! \A [ \p{nv=0}\p{nv=1}\p{nv=2}\p{nv=3}\p{nv=4}\p{nv=5} ] \z !xx в более ранних версиях Perl, поэтому в этом случае это функция просто упрощает и сокращает запись. Если бы мы не включили \A и \z, они бы сопоставлялись с такими вещами, как 1/2, потому что она содержит 1 (а также 2). В данном написании, оно соответствует таким вещам, как индексы, имеющие эти числовые значения. Если бы мы хотели только десятичные цифры с этими числовыми значениями, мы могли бы сказать,
qr! (?[ \d & \p{nv=/[0-5]/ ]) }!x \d избавляет от необходимости привязки шаблона, так как она заставляет результат соответствовать только [0-9], а [0-5] ещё больше его ограничивает.
Текст в примерах выше, заключенный в "/" символы, может быть практически любым регулярным выражением. Он независим от основного шаблона, поэтому не использует общие группы захвата и т. д. Разделители для него должны быть символами ASCII пунктуации, но он НЕ может быть ограничен "{", ни "}", ни содержать буквальный "}", так как он обозначает конец окружающего \p{}. Как и любой шаблон, некоторые другие разделители завершаются своими зеркальными образами. Это "(", "[, и "<". Если разделитель — это любой из "-", "_", "+", или "\", или тот же разделитель, что используется для окружающего шаблона, он должен быть предваряем обратным слэшем, как спереди, так и сзади.
Будьте осторожны при использовании "$" для указания соответствия концу строки. Его слишком легко принять за переменную пунктуации, такую как $/.
После конечного разделителя модификаторы использовать нельзя. Вместо этого используйте "(?adlupimnsx-imnsx)" в perlre и/или "(?adluimnsx-imnsx:pattern)" в perlre для задания модификаторов. Однако некоторые модификаторы запрещены в вашем подмаске с подстановкой. Единственный разрешённый модификатор набора символов — /aa; любые другие наборы символов, а также -m, p, и s запрещены. Указание модификаторов, таких как qr/.../gc, которые не допустимы в записи (?...), обычно вызывает предупреждение, но в подмасках с подстановкой их использование является ошибкой. Модификатор m неэффективен; всё, что соответствует, будет одной строкой.
По умолчанию ваше выражение сопоставляется без учёта регистра, как если бы был задан /i. Вы можете изменить это, указав (?-i) в вашем выражении.
Также существуют некоторые запрещённые операции. Вы не можете вложены вызовы \p{...} и \P{...} в пределах подмаски с подстановкой, а \G не имеет смысла, поэтому также запрещено.
И квантификатор * (или его эквивалент (0,}) запрещён.
Эта функция недоступна, когда левая часть предваряется Is_, а также для любых форм, помеченных как «Не рекомендуется» в "Не рекомендуется" в perluniprops.
Эта экспериментальная функция добавлена, чтобы начать реализацию https://www.unicode.org/reports/tr18/#Wildcard_Properties. Её использование вызовет предупреждение (включено по умолчанию) в категории experimental::uniprop_wildcards. Мы оставляем за собой право изменить её работу по мере накопления опыта.
Ваша подмаска может быть любой, но для её полезности она должна соответствовать, когда она вызывается либо с полным именем значения свойства с нижними подчёркиваниями (и/или пробелами в свойстве блока) и некоторыми заглавными буквами; либо со значением свойства в нижнем регистре со сжатыми пробелами и нижними подчёркиваниями. Например,
qr!\p{Blk=/Old I.*/}!
qr!\p{Blk=/oldi.*/}! будет соответствовать тем же самым вещам.
Другой пример, демонстрирующий, что в \p{...}, /x не требуется для добавления пробелов:
qr!\p{scx= /Hebrew|Greek/ }! Для безопасности мы должны были закрепить вышеприведённый пример, чтобы предотвратить сопоставление таких вещей, как Hebrew_Braille, но до сих пор нет имён скриптов такого рода. Если ни одно из допустимых значений свойства не соответствует вашему выражению, выдаётся предупреждение. Вероятно, в будущих версиях будет выдаваться предупреждение, если ваше выражение приводит к сопоставлению с каждым возможным кодовым точкой.
Начиная с версии 5.32, разрешено сопоставление свойств Имя, Алиасы имени и Названные последовательности. Они рассматриваются как одно комбинированное свойство, как это давно делается для \N{}. Расслабленное сопоставление не работает для них точно так же, как и для значений других свойств. Правила приведены в https://www.unicode.org/reports/tr44/tr44-24.html#UAX44-LM2. В результате Perl не пытается выполнять для вас нестрогое сопоставление, как это делает для других свойств. Все буквы в именах заглавные, но вы можете добавить (?i) в свою подмаску, чтобы игнорировать регистр. Если вы не уверены, где пробел, вы можете использовать ? в своей подмаске. Ни одно имя символа не содержит нижнего подчёркивания, поэтому не стоит пытаться сопоставить его. Использование дефисов особенно проблематично; обратитесь к ссылке выше. Однако обратите внимание, что по состоянию на Unicode 13.0 единственный скрипт, используемый в наше время, который имеет особенности с этим, — это тибетский; а также два корейских символа U+116C HANGUL JUNGSEONG OE и U+1180 HANGUL JUNGSEONG O-E. Unicode не гарантирует, что в будущем не будут добавлены имена, создающие проблемы с дефисами.
Использование подстановок для этих свойств является ресурсоёмким, учитывая сотни тысяч допустимых имён, которые необходимо проверить.
Пример использования подстановок свойства Имя:
qr!\p{name=/(SMILING|GRINNING) FACE/}! Ещё один пример:
qr/(?[ \p{name=\/CJK\/} - \p{ideographic} ])/ Это около 200 (на момент Unicode 13.0) символов CJK, которые не являются идеограммами.
Существуют определённые свойства, с которыми подмаски с подстановкой в настоящее время не работают:
Bidi Mirroring Glyph
Bidi Paired Bracket
Case Folding
Decomposition Mapping
Equivalent Unified Ideograph
Lowercase Mapping
NFKC Case Fold
Titlecase Mapping
Uppercase Mapping Также не реализована форма @unicode_property@.
Вот полный пример сопоставления адресов интернет-протокола IPV4 в любом (единичном) скрипте:
no warnings 'experimental::uniprop_wildcards';
# Can match a substring, so this intermediate regex needs to have
# context or anchoring in its final use. Using nt=de yields decimal
# digits. When specifying a subset of these, we must include \d to
# prevent things like U+00B2 SUPERSCRIPT TWO from matching
my $zero_through_255 =
qr/ \b (*sr: # All from same sript
(?[ \p{nv=0} & \d ])* # Optional leading zeros
( # Then one of:
\d{1,2} # 0 - 99
| (?[ \p{nv=1} & \d ]) \d{2} # 100 - 199
| (?[ \p{nv=2} & \d ])
( (?[ \p{nv=:[0-4]:} & \d ]) \d # 200 - 249
| (?[ \p{nv=5} & \d ])
(?[ \p{nv=:[0-5]:} & \d ]) # 250 - 255
)
)
)
\b
/x;
my $ipv4 = qr/ \A (*sr: $zero_through_255
(?: [.] $zero_through_255 ) {3}
)
\z
/x; Свойства пользовательских символов
Вы можете определить свои собственные двоичные свойства символов, определив подпрограммы, имена которых начинаются с "In" или "Is". (Функция набора регулярных выражений "(?[ ])" в perlre предоставляет альтернативу, которая позволяет определять более сложные свойства.) Подпрограммы могут быть определены в любом пакете. Они переопределяют любые свойства Unicode, выраженные теми же именами. Определённые пользователем свойства могут использоваться в конструкциях регулярных выражений \p{} и \P{}; если вы используете свойство, определённое пользователем из пакета, отличного от того, в котором вы находитесь, вы должны указать его пакет в конструкции \p{} или \P{}.
# assuming property IsForeign defined in Lang::
package main; # property package name required
if ($txt =~ /\p{Lang::IsForeign}+/) { ... }
package Lang; # property package name not required
if ($txt =~ /\p{IsForeign}+/) { ... } Подпрограммам передаётся один параметр, который равен 0, если сопоставление производится без учёта регистра, и не равен 0, если сопоставление производится с учётом регистра. Подпрограмма может возвращать разные значения в зависимости от значения флага. Но подпрограмма никогда не вызывается более одного раза для каждого значения флага (ноль против ненулевого). Возвращаемое значение сохраняется и используется вместо повторного вызова подпрограммы. Если подпрограмма определена во время компиляции выражения, она будет вызвана тогда; если нет, она будет вызвана в первый раз, когда её значение (для этого флага) потребуется во время выполнения.
Обратите внимание, что если регулярное выражение ненадёжно, Perl завершит работу вместо вызова подпрограммы, когда имя подпрограммы определяется ненадёжными данными.
Подпрограммы должны возвращать строку в специальном формате, состоящую из одной или нескольких строк, разделённых символом новой строки. Каждая строка должна быть одной из следующих:
-
Единое шестнадцатеричное число, обозначающее кодовый символ для включения.
-
Два шестнадцатеричных числа, разделённые горизонтальными пробелами (пробел или табуляция), обозначающие диапазон кодовых символов для включения. Второе число не должно быть меньше первого.
-
Элемент для включения, префикс
"+"; встроенное свойство символов (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символов, представляющее все символы в этом свойстве; два шестнадцатеричных кодовых символа для диапазона; или один шестнадцатеричный кодовый символ. -
Элемент для исключения, префикс
"-"; существующее свойство символов (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символов, представляющее все символы в этом свойстве; два шестнадцатеричных кодовых символа для диапазона; или один шестнадцатеричный кодовый символ. -
Элемент для отрицания, префикс
"!"; существующее свойство символов (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символов, представляющее все символы в этом свойстве; два шестнадцатеричных кодовых символа для диапазона; или один шестнадцатеричный кодовый символ. -
Элемент для пересечения, префикс
"&"; существующее свойство символов (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символов, для всех символов за исключением символов в свойстве; два шестнадцатеричных кодовых символа для диапазона; или один шестнадцатеричный кодовый символ.
Например, чтобы определить свойство, охватывающее японские слоговые азбуки (хирагана и катакана), можно определить
sub InKana {
return <<END;
3040\t309F
30A0\t30FF
END
} Представьте, что маркер конца здесь находится в начале строки. Теперь вы можете использовать \p{InKana} и \P{InKana}.
Вы также могли использовать существующие имена свойств блока:
sub InKana {
return <<'END';
+utf8::InHiragana
+utf8::InKatakana
END
} Предположим, вам нужно сопоставить только выделенные символы, а не исходные диапазоны блоков: другими словами, вы хотите удалить невыделенные символы:
sub InKana {
return <<'END';
+utf8::InHiragana
+utf8::InKatakana
-utf8::IsCn
END
} Отрицание полезно для определения (неудивительно!) отрицательных классов.
sub InNotKana {
return <<'END';
!utf8::InHiragana
-utf8::InKatakana
+utf8::IsCn
END
} Это будет сопоставлять все кодовые точки, не относящиеся к Unicode, так как каждая из них не входит в класс Кана. Если нужно, вы можете использовать пересечение, чтобы исключить их, как показано в этом изменённом примере:
sub InNotKana {
return <<'END';
!utf8::InHiragana
-utf8::InKatakana
+utf8::IsCn
&utf8::Any
END
} &utf8::Any должна быть последней строкой в определении.
Пересечение используется для получения общих символов, сопоставляемых двумя (или более) классами. Важно помнить, что не следует использовать "&" для первого набора; это означало бы пересечение с пустым набором, что привело бы к пустому набору. (Аналогично использование "-" для первого набора не оказывает никакого эффекта).
В отличие от сопоставлений свойств, не определяемых пользователем, предупреждение никогда не генерируется, если эти свойства сопоставляются с кодовой точкой, не относящейся к Unicode (см. "За пределами кодовых точек Unicode" ниже).
Определяемые пользователем отображения регистра (только для продвинутых пользователей)
Эта функция была удалена начиная с Perl 5.16. Модуль CPAN Unicode::Casing предоставляет лучшие функции без недостатков, которые имела эта функция. Если вы используете Perl, более раннюю чем 5.16, эта функция была наиболее полно задокументирована в версии 5.14 этой документации: http://perldoc.perl.org/5.14.0/perlunicode.html#User-Defined-Case-Mappings-%28for-serious-hackers-only%29
Кодировки символов для ввода и вывода
См. Encode.
Уровень поддержки Unicode регулярных выражений
Следующий список поддерживаемых функций Unicode для регулярных выражений описывает все функции, которые в настоящее время непосредственно поддерживаются ядром Perl. Ссылки на «Уровень N» и номера разделов относятся к UTS#18 «Регулярные выражения Unicode», версия 18, октябрь 2016.
Уровень 1 - Базовая поддержка Unicode
RL1.1 Hex Notation - Done [1]
RL1.2 Properties - Done [2]
RL1.2a Compatibility Properties - Done [3]
RL1.3 Subtraction and Intersection - Done [4]
RL1.4 Simple Word Boundaries - Done [5]
RL1.5 Simple Loose Matches - Done [6]
RL1.6 Line Boundaries - Partial [7]
RL1.7 Supplementary Code Points - Done [8] -
[1]
\N{U+...}и\x{...} -
[2]
\p{...}\P{...}. Это требование к минимальному списку свойств. Perl поддерживает их. См. R2.7 для других свойств. - [3]
-
В Perl есть
\d\D\s\S\w\W\X[:prop:][:^prop:], плюс все свойства, указанные в https://www.unicode.org/reports/tr18/#Compatibility_Properties. Они описаны выше в разделе "Другие свойства" - [4]
-
Функция regex sets в Perl, начиная с версии 5.18, достигает этого. См. "(?[ ])" в perlre.
-
[5]
\b\Bудовлетворяют большинству, но не всем, деталям этого требования, но\b{wb}и\B{wb}тоже, а также более строгое R2.3. - [6]
-
Обратите внимание, что Perl использует полное сведение к нижнему регистру при сопоставлении, а не простое:
Например,
U+1F88эквивалентноU+1F00 U+03B9, а не толькоU+1F80. Эта разница имеет значение в основном для определенных греческих заглавных букв с определёнными модификаторами: полное сведение к нижнему регистру разлагает букву, в то время как простое сведение к нижнему регистру сопоставило бы её с одним символом. - [7]
-
Причина, по которой это считается частично реализованным, состоит в том, что Perl имеет
qr/\b{lb}/иUnicode::LineBreak, которые соответствуют UAX#14 "Алгоритм разбиения строк Unicode". Конструктор регулярного выражения предоставляет поведение по умолчанию, в то время как модуль с более сложной функциональностью предоставляет настраиваемое разбиение строк.Но Perl рассматривает
\nв качестве разделителей начала и конца строки, в то время как Unicode определяет больше символов, которые следует так интерпретировать.Это:
VT U+000B (\v in C) FF U+000C (\f) CR U+000D (\r) NEL U+0085 LS U+2028 PS U+2029^и$в шаблонах регулярных выражений должны соответствовать всем этим, но не соответствуют. Эти символы также не должны, но должны, влиять на<>$., и номера строк скрипта.Кроме того, строки не должны разделяться внутри
CRLF(т.е. нет пустой строки между\rи\n). ДляCRLF, используйте уровень:crlf(см. PerlIO). -
[8] UTF-8/UTF-EBDDIC, используемый в Perl, позволяет не только
U+10000доU+10FFFF, но и значения, превышающиеU+10FFFF
Уровень 2 - Расширенная поддержка Unicode
RL2.1 Canonical Equivalents - Retracted [9]
by Unicode
RL2.2 Extended Grapheme Clusters and - Partial [10]
Character Classes with Strings
RL2.3 Default Word Boundaries - Done [11]
RL2.4 Default Case Conversion - Done
RL2.5 Name Properties - Done
RL2.6 Wildcards in Property Values - Partial [12]
RL2.7 Full Properties - Partial [13]
RL2.8 Optional Properties - Partial [14] - [9] Unicode переписал эту часть UTS#18, сказав, что получение канонического эквивалента (см. UAX#15 "Формы нормализации Unicode") в основном должно выполняться на уровне программиста. Используйте NFD для записи как ваших регулярных выражений, так и текста для их сопоставления (можно использовать Unicode::Normalize).
-
[10] Perl имеет
\Xи\b{gcb}. Unicode отозвал свой «режим кластера графем» и недавно добавил свойства строк, которые Perl пока не поддерживает. - [11] см. UAX#29 "Сегментация текста Unicode",
- [12] см. "Подстановочные знаки в значениях свойств" выше.
- [13] Perl поддерживает все свойства в базе данных символов Unicode (UCD). Он пока не поддерживает указанные свойства, полученные из других источников Unicode.
- [14] Единственное необязательное свойство, которое поддерживает Perl, — это Имя последовательности. Ни одно из этих свойств не входит в UCD.
Уровень 3 - Настроенная поддержка
Это было отозвано Unicode.
Кодировки Unicode
Символам Unicode присваиваются кодовые точки, представляющие собой абстрактные числа. Для использования этих чисел необходимы различные кодировки.
-
UTF-8
UTF-8 — это кодировка с переменной длиной (от 1 до 4 байтов), независимая от порядка байтов. В большинстве документации Perl, включая эту часть документа, термин «UTF-8» означает также «UTF-EBCDIC». Но в этом разделе «UTF-8» относится только к кодировке, используемой на платформах ASCII. Это надмножество 7-битного US-ASCII, поэтому все, закодированное в ASCII, имеет идентичное представление при кодировании в UTF-8.
Следующая таблица взята из Unicode 3.2.
Code Points 1st Byte 2nd Byte 3rd Byte 4th Byte U+0000..U+007F 00..7F U+0080..U+07FF * C2..DF 80..BF U+0800..U+0FFF E0 * A0..BF 80..BF U+1000..U+CFFF E1..EC 80..BF 80..BF U+D000..U+D7FF ED 80..9F 80..BF U+D800..U+DFFF +++++ utf16 surrogates, not legal utf8 +++++ U+E000..U+FFFF EE..EF 80..BF 80..BF U+10000..U+3FFFF F0 * 90..BF 80..BF 80..BF U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF U+100000..U+10FFFF F4 80..8F 80..BF 80..BFОбратите внимание на пробелы, помеченные «*» перед несколькими байтовыми записями выше. Они возникают из-за того, что легальная UTF-8 избегает несанкционированных кодировок: технически возможно закодировать одну кодовую точку в UTF-8 разными способами, но это запрещено, и всегда должна использоваться кратчайшая возможная кодировка (и именно это делает Perl).
Другой способ посмотреть на это — через биты:
Code Points 1st Byte 2nd Byte 3rd Byte 4th Byte 0aaaaaaa 0aaaaaaa 00000bbbbbaaaaaa 110bbbbb 10aaaaaa ccccbbbbbbaaaaaa 1110cccc 10bbbbbb 10aaaaaa 00000dddccccccbbbbbbaaaaaa 11110ddd 10cccccc 10bbbbbb 10aaaaaaКак вы можете видеть, все продолжения байтов начинаются с
"10", а старшие биты стартового байта показывают, сколько байтов содержится в закодированном символе.Оригинальная спецификация UTF-8 разрешала до 6 байтов, чтобы позволить кодирование чисел до
0x7FFF_FFFF. Perl продолжает разрешать их и расширил это до 13 байтов для кодирования кодовых точек до тех, которые могут уместиться в 64-битном слове. Однако Perl выведет предупреждение, если вы выведете что-либо из этого как непереносимое; и по строгим протоколам ввода UTF-8 они запрещены. Кроме того, теперь запрещено использовать кодовую точку, превышающую то, что может содержать целочисленная переменная со знаком на вашей системе. На 32-битных системах ASCII это означает0x7FFF_FFFF— максимальное значение (намного больше на 64-битных системах). -
UTF-EBCDIC
Как UTF-8, но EBCDIC-безопасный, так же как UTF-8 — ASCII-безопасный. Это означает, что все базовые символы (включая все символы, имеющие эквиваленты ASCII (например,
"A","0","%", и т. д.) одинаковы в EBCDIC и UTF-EBCDIC.)UTF-EBCDIC используется на платформах EBCDIC. Для представления данной кодовой точки он обычно требует больше байтов, чем UTF-8; самые большие кодовые точки Unicode занимают 5 байтов (вместо 4 в UTF-8), и, расширенный для 64-битных слов, он использует 14 байтов вместо 13 в UTF-8.
-
UTF-16, UTF-16BE, UTF-16LE, суррогаты и
BOM(маркеры порядка байтов)Следующие пункты в основном для справки и общего знания Unicode, Perl не использует эти конструкции в своих внутренних процессах.
Как и UTF-8, UTF-16 — это кодировка с переменной длиной, но там, где UTF-8 использует 8-битные кодовые единицы, UTF-16 использует 16-битные кодовые единицы. Все кодовые точки занимают либо 2, либо 4 байта в UTF-16: кодовые точки
U+0000..U+FFFFхранятся в одной 16-битной единице, а кодовые точкиU+10000..U+10FFFF— в двух 16-битных единицах. Последний случай использует суррогаты, первая 16-битная единица — высокий суррогат, а вторая — низкий суррогат.Суррогаты — это кодовые точки, выделенные для кодирования диапазона кодовых точек Unicode
U+10000..U+10FFFFв парах 16-битных единиц. Высокие суррогаты — это диапазонU+D800..U+DBFF, а низкие суррогаты — диапазонU+DC00..U+DFFF. Кодирование суррогатов$hi = ($uni - 0x10000) / 0x400 + 0xD800; $lo = ($uni - 0x10000) % 0x400 + 0xDC00;и декодирование
$uni = 0x10000 + ($hi - 0xD800) * 0x400 + ($lo - 0xDC00);Из-за 16-битной архитектуры UTF-16 зависит от порядка байтов. Сам UTF-16 может использоваться для вычислений в памяти, но если требуется хранение или передача, необходимо выбрать кодировки UTF-16BE (большая эндианность) или UTF-16LE (малая эндианность).
Это создаёт ещё одну проблему: что делать, если известно, что данные — UTF-16, но неизвестна эндианность? Маркеры порядка байтов, или
BOM'ы, являются решением этой проблемы. В Unicode зарезервирован специальный символ для использования в качестве маркера порядка байтов: символ с кодовой точкойU+FEFFявляетсяBOM.Хитрость заключается в том, что если вы прочитали
BOM, вы узнаете порядок байтов, так как, если он был записан на платформе с большой эндианностью, вы прочитаете байты0xFE 0xFF, а если на платформе с малой эндианностью, вы прочитаете байты0xFF 0xFE. (А если исходная платформа записывала UTF-8 на платформе ASCII, вы прочитаете байты0xEF 0xBB 0xBF.)Способ работы этой хитрости заключается в том, что символ с кодовой точкой
U+FFFEне должен находиться в потоках ввода, поэтому последовательность байтов0xFF 0xFEоднозначно является «BOM, представленной в формате малой эндианности», и не может быть «U+FFFE, представленной в формате большой эндианности».Суррогаты не имеют значения в Unicode вне их использования в парах для представления других кодовых точек. Тем не менее, Perl позволяет представлять их по отдельности внутри, например, сказав
chr(0xD801), чтобы все кодовые точки, а не только те, которые подходят для обмена, были представимы. Unicode определяет семантику для них, например, их"General_Category"—"Cs". Но поскольку их использование несколько опасно, Perl выведет предупреждение (используя категорию предупреждений"surrogate", которая является подкатегорией"utf8"), если есть попытка сделать такие вещи, как взять нижний регистр одного из них или сопоставить регистронезависимо, или вывести их. (Но не пробуйте это на Perls до версии 5.14.) -
UTF-32, UTF-32BE, UTF-32LE
Семейство UTF-32 очень похоже на семейство UTF-16, за исключением того, что единицы 32-битные, и поэтому схема суррогатов не нужна. UTF-32 — это кодировка с фиксированной длиной.
BOMсигнатуры составляют0x00 0x00 0xFE 0xFFдля BE и0xFF 0xFE 0x00 0x00для LE. -
UCS-2, UCS-4
Устаревшие кодировки с фиксированной длиной, определённые стандартом ISO 10646. UCS-2 — 16-битная кодировка. В отличие от UTF-16, UCS-2 не расширяется за пределы
U+FFFF, так как не использует суррогатов. UCS-4 — 32-битная кодировка, функционально идентичная UTF-32 (различие состоит в том, что UCS-4 не запрещает ни суррогаты, ни кодовые точки, превышающие0x10_FFFF). -
UTF-7
7-битная безопасная (не 8-битная) кодировка, которая полезна, если транспорт или хранение не безопасны в отношении 8 бит. Определена RFC 2152.
Кодовые точки, не являющиеся символами
В Юникоде 66 кодовых точек зарезервированы как «несимвольные кодовые точки». У них все Unassigned (Cn) "General_Category", и ни одному из них никогда не будет назначен символ. Это 32 кодовых точки между U+FDD0 и U+FDEF включительно, и 34 кодовые точки:
U+FFFE U+FFFF
U+1FFFE U+1FFFF
U+2FFFE U+2FFFF
...
U+EFFFE U+EFFFF
U+FFFFE U+FFFFF
U+10FFFE U+10FFFF До Юникода версии 7.0, несимвольные кодовые точки были «запрещены для использования в открытом обмене данными Юникода», так что код, обрабатывающий эти потоки, мог использовать эти кодовые точки как сигналы, которые могли быть смешаны с данными символов и всегда отличались от этих данных. (Выделение выше и в следующем абзаце добавлено в этом документе.)
В Юникоде версии 7.0 формулировка изменилась так, что они «не рекомендуются для использования в открытом обмене данными Юникода». Стандарт 7.0 продолжает говорить:
"Если несимвольная кодовая точка получена при открытом обмене, приложение не обязано её интерпретировать каким-либо образом. Однако, хорошей практикой является распознавание её как несимвольной и принятие соответствующих мер, таких как замена её на U+FFFD символ замены, чтобы указать на проблему в тексте. Не рекомендуется просто удалять несимвольные кодовые точки из такого текста из-за потенциальных проблем безопасности, вызванных удалением неинтерпретированных символов. (См. пункт соответствия C7 в разделе 3.2, Требования к соответствию, и Технический отчет Юникода №36, «Учёт безопасности в Юникоде»)."
Это изменение было сделано, потому что было обнаружено, что различные коммерческие инструменты, такие как редакторы или инструменты для управления исходным кодом, были написаны таким образом, что не обрабатывали файлы программ, использующие эти кодовые точки, фактически исключая их использование практически полностью! И это никогда не было намерением. Они всегда должны были быть применимы внутри приложения или в сотрудничающей группе приложений, по желанию.
Если вы пишете код, например, редактор, который должен уметь обрабатывать любые данные Юникода, тогда вы не должны использовать эти кодовые точки сами и вместо этого позволять их в вводе. Если вам нужны сигналы, они должны быть чем-то, что не является допустимым Юникодом. Для данных UTF-8 вы можете использовать байты 0xC0 и 0xC1 в качестве сигналов, так как они никогда не появляются в правильно сформированном UTF-8. (Существуют аналоги для UTF-EBCDIC). Вы также можете хранить свои кодовые точки Юникода в целочисленных переменных и использовать отрицательные значения в качестве сигналов.
Если вы не пишете такой инструмент, то решение о том, принимать ли несимвольные кодовые точки как ввод, зависит от вас (хотя Стандарт рекомендует этого не делать). Если вы выполняете строгую проверку входных потоков с помощью Perl, эти кодовые точки по-прежнему запрещены. Это для поддержания обратной совместимости (иначе могут открыться потенциальные уязвимости безопасности, так как неопытное приложение, написанное с предположением, что несимвольные кодовые точки будут отфильтрованы перед получением, теперь, без предупреждения, может начать их получать). Для выполнения строгой проверки вы можете использовать слой :encoding('UTF-8').
Perl продолжает предупреждать (используя категорию предупреждений "nonchar", которая является подкатегорией "utf8" ) если попытка вывести несимвольные кодовые точки.
За пределами кодовых точек Юникода
Максимальная кодовая точка Юникода — U+10FFFF, и Юникод определяет операции только для кодовых точек до этого значения. Но Perl работает с кодовыми точками до максимального допустимого знакового числа, доступного в системе. Однако Perl не будет принимать их из входных потоков, если не используются нестрогие правила, и будет предупреждать (используя категорию предупреждений "non_unicode", которая является подкатегорией "utf8") если какие-либо будут выведены.
Так как правила Юникода не определены для этих кодовых точек, если выполняется операция Юникода над ними, Perl использует то, что, по нашему мнению, являются разумными правилами, при этом, как правило, выдает предупреждение, используя категорию "non_unicode". Например, uc("\x{11_0000}") сгенерирует такое предупреждение, вернув входной параметр в качестве результата, так как Perl определяет верхний регистр каждой не-Юникод кодовой точки как саму кодовую точку. (Все операции изменения регистра, а не только перевод в верхний регистр, работают таким образом.)
Ситуация с соответствием свойств Юникода в регулярных выражениях, конструкций \p{} и \P{} для этих кодовых точек не столь однозначна, и то, как они обрабатываются, изменилось по мере накопления опыта.
Один из вариантов — рассматривать любой совпадение с этими кодовыми точками как неопределённое. Но так как Perl не имеет понятия о неопределённом совпадении, он преобразует это в отказ или FALSE. Это почти, но не совсем, то, что Perl делал с версии 5.14 (когда использование этих кодовых точек стало в целом надёжным) до версии 5.18. Разница в том, что Perl рассматривал все \p{} совпадения как проваленные, но все \P{} совпадения как успешные.
Одна из проблем заключается в том, что это приводит к неожиданным и запутанным результатам в некоторых случаях:
chr(0x110000) =~ \p{ASCII_Hex_Digit=True} # Failed on <= v5.18
chr(0x110000) =~ \p{ASCII_Hex_Digit=False} # Failed! on <= v5.18 То есть он рассматривал оба совпадения как неопределённые и преобразовывал это в ложь (выдавая предупреждение в каждом случае). Первый случай — ожидаемый результат, но второй, вероятно, не интуитивен: «Как оба могут быть ложными, если они являются дополнениями?» Другая проблема заключалась в том, что реализация оптимизировала многие соответствия свойств Юникода до уже существующих более простых и быстрых операций, которые не генерируют предупреждение. Мы решили не отказываться от этих оптимизаций, которые помогают подавляющему большинству совпадений, только для того, чтобы сгенерировать предупреждение в маловероятном случае, если сравнивается кодовая точка, превышающая Юникод.
В результате этих проблем, начиная с версии 5.20, Perl рассматривает не-Юникод кодовые точки как типичные неназначенные символы Юникода и выполняет соответствие соответственно. (Примечание: Юникод имеет атипичные неназначенные кодовые точки. Например, у него есть несимвольные кодовые точки и такие, которые, если они будут назначены, будут написаны справа налево, как арабские и иврит. Perl предполагает, что у любой не-Юникод кодовой точки нет никаких атипичных свойств.)
Perl, в большинстве случаев, выведет предупреждение при сопоставлении не-Юникод кодовой точки со свойством Юникода, когда результатом является TRUE для \p{}, и FALSE для \P{}. Например:
chr(0x110000) =~ \p{ASCII_Hex_Digit=True} # Fails, no warning
chr(0x110000) =~ \p{ASCII_Hex_Digit=False} # Succeeds, with warning В обоих этих примерах символ, с которым производится сопоставление, не является Юникодом, поэтому Юникод не определяет, как он должен сопоставляться. Это явно не шестнадцатеричная цифра ASCII, поэтому в первом примере очевидно, что он должен дать сбой, и так оно и происходит без предупреждения. Но можно утверждать, что во втором примере должен быть неопределённый, следовательно, FALSE, результат. Поэтому для него генерируется предупреждение.
Таким образом, предупреждение генерируется во многих случаях реже, чем в более ранних версиях Perl, и только тогда, когда результат может быть неоднозначным. Оказалось, что ни одна из оптимизаций Perl (или которые вряд ли будут сделаны) не приводит к пропуску предупреждения, поэтому он решает обе проблемы более раннего подхода Perl. Наиболее часто используемое свойство, которое затронуто этим изменением, это \p{Unassigned}, которое является сокращением для \p{General_Category=Unassigned}. Начиная с версии 5.20, все не-Юникод кодовые точки считаются Unassigned. В более ранних версиях совпадения не удавались, потому что результат считался неопределённым.
Единственное место, где предупреждение не генерируется, когда оно могло бы быть, — это если оптимизации приведут к тому, что вообще не будет предпринята попытка сопоставления. Например, Perl может понять, что для того, чтобы строка соответствовала определённому шаблону регулярного выражения, строка должна содержать подстроку "foobar". Перед попыткой сопоставления Perl может искать эту подстроку, и если её не найдёт, сразу отклонит сопоставление, не пытаясь его вообще выполнить; поэтому предупреждение не генерируется, даже если строка содержит кодовую точку, превышающую Юникод.
Это поведение более «делает то, что я имею в виду» по сравнению с более ранними версиями Perl для большинства приложений. Но это ловит меньше проблем для кода, который должен строго соответствовать Юникоду. Поэтому доступен дополнительный режим работы для адаптации такого кода. Этот режим включён, если шаблон регулярного выражения компилируется в лексическом пространстве, где категория предупреждений "non_unicode" сделана фатальной, например, следующим образом:
use warnings FATAL => "non_unicode" (см. warnings). В этом режиме работы Perl выведет предупреждение для всех соответствий с не-Юникод кодовой точкой (а не только спорных), и пропустит оптимизации, которые могут привести к тому, что предупреждение не будет выведено. (В настоящее время предупреждение всё равно не выдаётся, если сопоставление вообще не предпринимается, как в примере "foobar" выше.)
В заключение, Perl теперь обычно рассматривает не-Юникод кодовые точки как типичные неназначенные кодовые точки Юникода для сопоставления регулярных выражений, выдавая предупреждение только в случае, если неясно, каким должен быть результат. Однако, если это предупреждение сделано фатальным, оно не пропускается.
Есть одно исключение из всего этого. \p{All} выглядит как свойство Юникода, но это расширение Perl, которое определено как истинное для всех возможных кодовых точек, Юникод или нет, поэтому предупреждение никогда не генерируется при сопоставлении этого с не-Юникод кодовой точкой. (До версии 5.20 это был точный синоним \p{Any}, сопоставляющий кодовые точки 0 по 0x10FFFF.)
Последствия использования Юникода с точки зрения безопасности
Сначала прочитайте Учёт безопасности в Юникоде.
Также обратите внимание на следующее:
-
Неправильно сформированный UTF-8
UTF-8 очень структурирован, поэтому многие комбинации байтов недопустимы. В прошлом Perl пытался продолжить работу и каким-то образом интерпретировать недопустимые комбинации, но это может привести к уязвимостям безопасности, поэтому теперь, если ядру Perl нужно обработать недопустимую комбинацию, оно либо выведет фатальную ошибку, либо заменит эти байты последовательностью, которая образует символ замены Юникода, для чего Юникод его и создал.
Каждая кодовая точка может быть представлена более чем одной возможной синтаксически корректной последовательностью UTF-8. Вначале как Юникод, так и Perl считали все эти последовательности допустимыми, но теперь все последовательности, более длинные, чем кратчайшая, считаются неправильно сформированными.
Юникод считает многие кодовые точки недопустимыми или нежелательными. Perl, как правило, принимает их, после того как они пройдут через любые входные фильтры, которые могут пытаться их исключить. Эти вопросы обсуждались выше (см. «Суррогаты» в UTF-16 в "Кодировки Юникода", "Несимвольные кодовые точки" и "За пределами кодовых точек Юникода").
-
Сопоставление шаблонов регулярных выражений с Юникодом может вас удивить, если вы не знакомы с Юникодом. Начиная с Perl 5.14, доступны несколько модификаторов шаблонов для управления этим, называемые модификаторами наборов символов. Подробности приведены в "Модификаторы набора символов" в perlre.
Как обсуждалось ранее, Perl имеет одну ногу (две копыта?) в двух мирах: старом мире ASCII и однобайтовых локалей и новом мире Юникода, обновляясь по мере необходимости. Если ваш устаревший код не использует Юникод явно, никаких автоматических переключений на Юникод не должно происходить.
Юникод в Perl на платформах EBCDIC
Юникод поддерживается на платформах EBCDIC. См. perlebcdic.
Если вопросы ASCII против EBCDIC не обсуждаются конкретно, ссылки на кодировку UTF-8 в этом документе и в других местах должны читаться как ссылки на UTF-EBCDIC на платформах EBCDIC. См. "Юникод и UTF" в perlebcdic.
Поскольку UTF-EBCDIC очень похож на UTF-8, различия в основном скрыты от вас; use utf8 (а НЕ что-то вроде use utfebcdic) объявляет, что сценарий находится в "родном" 8-битном кодировании Unicode платформы. (Аналогично для ":utf8" слоя.)
Локали
См. "Unicode и UTF-8" в perllocale
Когда Unicode не используется
Существует множество мест, где Unicode (в том или ином кодировании) может передаваться в качестве аргументов или получаться в качестве результатов, или и то, и другое в Perl, но это не так, несмотря на то, что Perl имеет обширные возможности ввода и вывода в Unicode, а также несколько других "точек входа", таких как массив %%%CODE_BLOCK_573%% (который иногда может интерпретироваться как UTF-8).
Следующие — это такие интерфейсы. Также см. "Ошибка Unicode". Для всех этих интерфейсов Perl в настоящее время (по состоянию на v5.16.0) просто предполагает строку байтов как аргументы и результаты или строку UTF-8, если был использован (устаревший) оператор encoding.
Одна из причин, по которой Perl не пытается разрешить роль Unicode в этих ситуациях, заключается в том, что ответы сильно зависят от операционной системы и файловой системы(систем). Например, возможность использования имен файлов в Unicode и в каком именно кодировании — это не совсем понятие переносимости. Аналогично для qx и system: насколько хорошо интерфейс командной строки (и какой из них?) будет обрабатывать Unicode?
-
chdir,chmod,chown,chroot,exec,link,lstat,mkdir,rename,rmdir,stat,symlink,truncate,unlink,utime,-X -
%ENV -
glob(также известный как<*>) -
open,opendir,sysopen -
qx(также известный как оператор backtick),system -
readdir,readlink
Ошибка Unicode
Термин "ошибка Unicode" был применён к несоответствию кодовых точек в блоке Latin-1 Supplement, то есть между 128 и 255. Без указанной локали, в отличие от всех остальных символов или кодовых точек, эти символы могут иметь очень разные семантики в зависимости от действующих правил. (Символы, кодовые точки которых превышают 255, заставляют работать правила Unicode; в то время как правила для символов ASCII одинаковы как в правилах ASCII, так и в правилах Unicode.)
В соответствии с правилами Unicode эти символы верхнего латинского набора интерпретируются как кодовые точки Unicode, что означает, что они имеют ту же семантику, что и Latin-1 (ISO-8859-1) и управляющие символы C1.
Как поясняется в "Правила ASCII против правил Unicode", в соответствии с правилами ASCII они считаются неназначенными символами.
Это может привести к неожиданным результатам. Например, семантика строки может внезапно измениться, если к ней добавляется кодовая точка, превышающая 255, что изменяет правила с ASCII на Unicode. В качестве примера рассмотрите следующую программу и её вывод:
$ perl -le'
no feature "unicode_strings";
$s1 = "\xC2";
$s2 = "\x{2660}";
for ($s1, $s2, $s1.$s2) {
print /\w/ || 0;
}
'
0
0
1 Если в s1 или s2 нет \w, почему у их конкатенации есть один?
Эта аномалия обусловлена попыткой Perl не нарушать работу более старых программ, не использующих Unicode, а также желанием Perl обеспечить бесшовную поддержку Unicode. Но результат оказался не бесшовным. (Кстати, вы можете выбрать, чтобы получать предупреждения при таких событиях. См. encoding::warnings.)
use feature 'unicode_strings' был добавлен, начиная с Perl v5.12, для решения этой проблемы. Он затрагивает следующие моменты:
-
Изменение регистра скаляра, то есть использование
uc(),ucfirst(),lc(), иlcfirst(), или\L,\U,\uи\lв контексте двойных кавычек, таких как подстановки в регулярных выражениях.В рамках
unicode_strings, начиная с Perl 5.12.0, обычно используются правила Unicode. См. "lc" в perlfunc для получения подробностей о том, как это работает в сочетании с различными другими операторами. -
Использование нечувствительного к регистру (
/i) сопоставления с регулярными выражениями.Начиная с Perl 5.14.0, регулярные выражения, скомпилированные в рамках
unicode_strings, используют правила Unicode, даже если они выполняются или компилируются в более крупные регулярные выражения вне этого контекста. -
Сопоставление любого из нескольких свойств в регулярных выражениях.
Эти свойства:
\b(без фигурных скобок),\B(без фигурных скобок),\s,\S,\w,\W, и все классы символов Posix кроме[[:ascii:]].Начиная с Perl 5.14.0, регулярные выражения, скомпилированные в рамках
unicode_strings, используют правила Unicode, даже если они выполняются или компилируются в более крупные регулярные выражения вне этого контекста. -
В
quotemetaили его эквиваленте в строке\Q.Начиная с Perl 5.16.0, используются согласованные правила цитирования в рамках
unicode_strings, как описано в "quotemeta" в perlfunc. До этого или вне этого контекста, кодовые точки, превышающие 127, не цитируются в строках, закодированных в UTF-8, но в строках, закодированных в байтах, кодовые точки от 128 до 255 всегда цитируются. -
В операторе
..или диапазона.Начиная с Perl 5.26.0, оператор диапазона в строках последовательно обрабатывает их длину в рамках
unicode_strings. До этого или вне этого контекста, он мог создавать строки, длина которых в символах превышала длину правой части, где правая часть занимала больше байтов, чем правильная конечная точка диапазона. -
В
split- специальном случае разделения по пробелам.Начиная с Perl 5.28.0, функция
splitс шаблоном, указанным как строка, содержащая один пробел, последовательно обрабатывает символы пробела в рамкахunicode_strings. До этого или вне этого контекста, символы, являющиеся пробелами в соответствии с правилами Unicode, но не в соответствии с правилами ASCII, обрабатывались как содержимое поля, а не разделители полей, когда они появлялись в строках, закодированных в байтах.
Из вышеизложенного видно, что влияние unicode_strings увеличивалось в течение нескольких версий Perl. (И поддержка Unicode Perl продолжает совершенствоваться; лучше использовать последнюю доступную версию, чтобы получить максимально полные и точные результаты.) Обратите внимание, что unicode_strings автоматически выбирается, если вы use v5.12 или выше.
Для версий Perl, предшествующих описанным выше, или когда строка передаётся функции вне области действия unicode_strings, см. следующий раздел.
Принудительное использование Unicode в Perl (или отключение Unicode в Perl)
Иногда (см. "Когда Unicode не используется" или "Ошибка Unicode") бывают ситуации, когда вам просто нужно преобразовать строку байтов в UTF-8 или наоборот. Для этого можно использовать стандартный модуль Encode или низкоуровневые вызовы utf8::upgrade($bytestring) и utf8::downgrade($utf8string[, FAIL_OK]).
Обратите внимание, что utf8::downgrade() может завершиться неудачей, если строка содержит символы, которые не помещаются в один байт.
Вызов любой из функций для строки, которая уже находится в желаемом состоянии, является пустой операцией.
"Правила ASCII против правил Unicode" содержит все способы, как строка использует правила Unicode.
Использование Unicode в XS
См. "Поддержка Unicode" в perlguts для введения в Unicode на уровне XS и "Поддержка Unicode" в perlapi для подробностей API.
Модификация Perl для работы с более ранними версиями Unicode (только для очень опытных программистов)
Perl по умолчанию поставляется с последней поддерживаемой версией Unicode, но цель заключается в том, чтобы вы могли переключиться на любую более раннюю версию. В Perl v5.20 и v5.22 самая ранняя используемая версия — Unicode 5.1. Perl v5.18 и v5.24 могут обрабатывать все более ранние версии.
Загрузите файлы нужной версии Unicode с веб-сайта Unicode https://www.unicode.org). Эти файлы должны заменить существующие файлы в lib/unicore в дереве исходного кода Perl. Следуйте инструкциям в файле README.perl в этом каталоге, чтобы изменить некоторые из их имён, а затем выполните сборку Perl (см. INSTALL).
Портирование кода из perl-5.6.X
Версии Perl, начиная с 5.8, имеют другую модель Unicode, чем 5.6. В 5.6 программисту необходимо было использовать оператор utf8 для объявления, что данный контекст ожидает обработки данных Unicode, и необходимо было убедиться, что в этот контекст поступают только данные Unicode. Если у вас есть код, работающий с 5.6, вам понадобятся некоторые из следующих корректировок вашего кода. Примеры написаны таким образом, что код будет продолжать работать под 5.6, поэтому вы можете смело их попробовать.
-
Поток файла, который должен считывать или записывать UTF-8
if ($] > 5.008) { binmode $fh, ":encoding(UTF-8)"; } -
Скаляр, который будет передан какому-либо расширению
Независимо от того,
Compress::Zlib,Apache::Requestили любого расширения, в котором нет упоминания о Unicode в документации, вам необходимо убедиться, что флаг UTF8 снят. Обратите внимание, что на момент написания этого текста (январь 2012 года) указанные модули не поддерживают UTF-8. Проверьте документацию, чтобы убедиться, что это всё ещё актуально.if ($] > 5.008) { require Encode; $val = Encode::encode("UTF-8", $val); # make octets } -
Скаляр, полученный обратно из расширения
Если вы уверены, что скаляр возвращается как UTF-8, вы, скорее всего, захотите восстановить флаг UTF8:
if ($] > 5.008) { require Encode; $val = Encode::decode("UTF-8", $val); } -
То же самое, если вы абсолютно уверены, что это UTF-8
if ($] > 5.008) { require Encode; Encode::_utf8_on($val); } -
Обёртка для DBI
fetchrow_arrayиfetchrow_hashrefЕсли база данных содержит только UTF-8, оберточная функция или метод — удобный способ заменить все ваши вызовы
fetchrow_arrayиfetchrow_hashref. Оберточная функция также упростит адаптацию к будущим усовершенствованиям в вашем драйвере базы данных. Обратите внимание, что на момент написания этого текста (январь 2012 года) в DBI нет стандартизированного способа обработки данных UTF-8. Проверьте документацию DBI, чтобы убедиться, что это всё ещё актуально.sub fetchrow { # $what is one of fetchrow_{array,hashref} my($self, $sth, $what) = @_; if ($] < 5.008) { return $sth->$what; } else { require Encode; if (wantarray) { my @arr = $sth->$what; for (@arr) { defined && /[^\000-\177]/ && Encode::_utf8_on($_); } return @arr; } else { my $ret = $sth->$what; if (ref $ret) { for my $k (keys %$ret) { defined && /[^\000-\177]/ && Encode::_utf8_on($_) for $ret->{$k}; } return $ret; } else { defined && /[^\000-\177]/ && Encode::_utf8_on($_) for $ret; return $ret; } } } } -
Большой скаляр, который, как вы знаете, может содержать только ASCII
Скаляры, содержащие только ASCII и помеченные как UTF-8, иногда затрудняют работу программы. Если вы опознаёте такую ситуацию, просто удалите флаг UTF8:
utf8::downgrade($val) if $] > 5.008;
ОШИБКИ
См. также "Ошибка Unicode" выше.
Взаимодействие с расширениями
При обмене данными между Perl и расширением, расширение должно понимать флаг UTF8 и действовать соответствующим образом. Если расширение не распознаёт этот флаг, есть вероятность, что оно вернёт данные с неправильными флагами.
Поэтому, если вы работаете с данными Unicode, проконсультируйтесь с документацией каждого используемого модуля, если есть какие-либо проблемы с обменом данными Unicode. Если в документации вообще нет упоминаний о Unicode, предполагайте худшее и, вероятно, посмотрите исходный код, чтобы понять, как реализован модуль. Модули, написанные полностью на Perl, не должны вызывать проблем. Модули, которые напрямую или косвенно обращаются к коду, написанному на других языках программирования, находятся под риском.
Для затронутых функций простая стратегия, чтобы избежать повреждения данных, заключается в том, чтобы всегда явно указывать кодировку обмениваемых данных. Выберите кодировку, которую расширение может обработать. Преобразуйте аргументы, передаваемые расширениям, в эту кодировку и преобразуйте результаты обратно из этой кодировки. Напишите оберточные функции, которые выполнят преобразования за вас, так чтобы вы могли позже изменить функции, когда расширение будет поддерживать это.
В качестве примера предположим, что популярная Foo::Bar::escape_html функция ещё не обрабатывает данные Unicode. Функция-обёртка преобразует аргумент в чистый UTF-8 и преобразует результат обратно в внутреннее представление Perl, как показано ниже:
sub my_escape_html ($) {
my($what) = shift;
return unless defined $what;
Encode::decode("UTF-8", Foo::Bar::escape_html(
Encode::encode("UTF-8", $what)));
} Иногда, когда расширение не преобразует данные, а только хранит и извлекает их, вы сможете использовать иначе опасную функцию Encode::_utf8_on(). Предположим, популярное расширение Foo::Bar, написанное на C, предоставляет метод param, который позволяет хранить и извлекать данные в соответствии с этими прототипами:
$self->param($name, $value); # set a scalar
$value = $self->param($name); # retrieve a scalar Если оно ещё не поддерживает какую-либо кодировку, можно написать производный класс с методом param,
sub param {
my($self,$name,$value) = @_;
utf8::upgrade($name); # make sure it is UTF-8 encoded
if (defined $value) {
utf8::upgrade($value); # make sure it is UTF-8 encoded
return $self->SUPER::param($name,$value);
} else {
my $ret = $self->SUPER::param($name);
Encode::_utf8_on($ret); # we know, it is UTF-8 encoded
return $ret;
}
} Некоторые расширения предоставляют фильтры на точках входа/выхода данных, такие как DB_File::filter_store_key и аналогичные. Обращайте внимание на такие фильтры в документации ваших расширений; они могут значительно упростить переход к данным Unicode.
Скорость
Некоторые функции работают медленнее при работе со строками, закодированными в UTF-8, чем со строками, закодированными в байтах. Все функции, которым необходимо перемещаться по символам, таким как length(), substr() или index(), или сопоставление регулярных выражений, могут работать намного быстрее, когда основополагающие данные закодированы в байтах.
В Perl 5.8.0 медлительность часто была довольно заметной; в Perl 5.8.1 была введена схема кэширования, которая улучшила ситуацию. В общем, операции со строками, закодированными в UTF-8, всё ещё медленнее. Например, свойства Unicode (классы символов), такие как \p{Nd}, известны тем, что они значительно медленнее (в 5-20 раз) своих более простых аналогов, таких как [0-9] (хотя, существует сотни символов Unicode, соответствующих Nd, по сравнению с 10 ASCII символами, соответствующими [0-9]).
СМОТРИТЕ ТАКЖЕ
perlunitut, perluniintro, perluniprops, Encode, open, utf8, bytes, perlretut, "${^UNICODE}" в perlvar, https://www.unicode.org/reports/tr44).
© 1993–2023 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.38.0/perlunicode