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 начинается с байтов, которые составляют кодировку Unicode BYTE ORDER MARK (
BOM, см. «Кодировки Unicode»), эти байты полностью игнорируются. - UTF-16 скрипты распознаются автоматически
-
Если скрипт Perl начинается с Unicode
BOM(UTF-16LE, UTF16-BE), или если скрипт похож на не-BOM-размеченный 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()производит реверс по символам, а не по байтам. -
Операторы битовых строк
& | ^ ~и (начиная с версии 5.22)&. |. ^. ~.могут работать со строками битовых строк, закодированных в UTF-8, но это может привести к неожиданным результатам, если какие-либо из строк содержат кодовые точки выше 0xFF. Начиная с версии 5.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 затронуто больше операций. См. "The "Unicode Bug"".
-
Внутри области действия
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).
Этот раздел содержит подробности обо всех расширениях, которые не являются просто синонимами свойств Юникода в составной форме (для этих свойств вам нужно обратиться к стандарту Юникода).
END_OF_DOCUMENT_MARKER-
\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 Character Classes" в 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. Обычно этого не нужно.Некоторые реализации свойства Age, отличные от Perl, могут изменить его значение, чтобы оно было таким же, как у свойства 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}). Разница в том, что при сопоставлении без учета регистра они соответствуют тем же, что и\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 Character Classes" в 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. Мы оставляем за собой право изменить её работу по мере накопления опыта.
Ваша подмаска может быть практически любой, но для того, чтобы она имела какое-то значение, она должна совпадать при вызове с a) полным именем значения свойства с нижними подчеркиваниями (и/или пробелами в свойстве «Блок») и некоторыми заглавными буквами; или b) значением свойства во всех строчных буквах со сжатыми пробелами и нижними подчеркиваниями. Например,
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, если сопоставление происходит с учётом регистра, и ненулевой, если сопоставление происходит без учёта регистра. Подпрограмма может возвращать различные значения в зависимости от значения флага, и один набор значений будет неизменно действовать для всех сопоставлений с учётом регистра, а другой — для всех сопоставлений без учёта регистра.
Обратите внимание, что если регулярное выражение заражено, Perl завершит работу, а не вызовет подпрограмму, когда имя подпрограммы определяется заражёнными данными.
Подпрограммы должны возвращать строку в специальном формате с одной или несколькими строками, разделёнными символом новой строки. Каждая строка должна быть одной из следующих:
-
Единое шестнадцатеричное число, обозначающее кодовый пункт для включения.
-
Два шестнадцатеричных числа, разделённые горизонтальным пробелом (пробел или табуляция), обозначающие диапазон кодовых пунктов для включения. Второе число не должно быть меньше первого.
-
Элемент для включения, префикс
"+": встроенное свойство символа (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символа для представления всех символов в этом свойстве; два шестнадцатеричных кодовых пункта для диапазона; или единственный шестнадцатеричный кодовый пункт. -
Элемент для исключения, префикс
"-": существующее свойство символа (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символа для представления всех символов в этом свойстве; два шестнадцатеричных кодовых пункта для диапазона; или единственный шестнадцатеричный кодовый пункт. -
Элемент для отрицания, префикс
"!": существующее свойство символа (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символа для представления всех символов в этом свойстве; два шестнадцатеричных кодовых пункта для диапазона; или единственный шестнадцатеричный кодовый пункт. -
Элемент для пересечения, префикс
"&": существующее свойство символа (префикс"utf8::") или полностью квалифицированное (включая имя пакета) пользовательское свойство символа для представления всех символов, кроме символов в этом свойстве; два шестнадцатеричных кодовых пункта для диапазона; или единственный шестнадцатеричный кодовый пункт.
Например, для определения свойства, которое охватывает оба японских слоговых алфавита (хирагана и катакана), вы можете определить
sub InKana {
return <<END;
3040\t309F
30A0\t30FF
END
} Представьте, что маркер окончания here-документа находится в начале строки. Теперь вы можете использовать \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 должно быть последней строкой в определении.
Пересечение используется, в общем, для получения общих символов, сопоставляемых двумя (или более) классами. Важно помнить, что не следует использовать "&" для первого набора; это было бы пересечение ни с чем, что приводит к пустому набору. (Аналогично, использование "-" для первого набора ничего не делает).
В отличие от сопоставлений свойств, не являющихся пользовательскими, \p{} никогда не генерируется предупреждение, если эти свойства сопоставляются с кодовой точкой, не являющейся 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 Regular Expressions», версия 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]
-
Функция набора правил регулярных выражений
"(?[...])"начиная с версии 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-битной единицей является высокий суррогат, а второй — низкий суррогат.Суррогаты — это кодовые точки, отведённые для кодирования диапазона
U+10000..U+10FFFFкодовых точек Unicode в парах 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. (И если исходная платформа записывала в ASCII платформе UTF-8, вы прочитаете байты0xEF 0xBB 0xBF.)Символы-суррогаты не имеют смысла в Unicode за пределами их использования в парах для представления других кодовых точек. Однако Perl позволяет представлять их по отдельности во внутренней работе, например, сказав
chr(0xD801), так что все кодовые точки, а не только те, которые подходят для открытого обмена, могут быть представлены. Unicode определяет семантику для них, например, их"General_Category"равно"Cs". Но поскольку их использование несколько опасно, Perl будет выдавать предупреждение (используя категорию предупреждений"surrogate", которая является подкатегорией"utf8"), если будет попытка сделать что-то вроде взятия строчных букв, сопоставления без учёта регистра или вывода. -
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 вы можете использовать байты 0xC1 и 0xC2 в качестве меток, так как они никогда не появляются в хорошо сформированных данных 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-битное кодирование Юникода платформы. (Аналогично для уровня ":utf8".)
Локали
См. "Unicode и UTF-8" в perllocale
Когда Юникод не используется
Существует множество мест, где Юникод (в каком-либо кодировании) может быть передан в качестве аргументов или получен в результате, или и то, и другое в Perl, но этого не происходит, несмотря на то, что Perl имеет обширные способы ввода и вывода в Юникоде и некоторые другие «точки входа», такие как массив @ARGV (который иногда может интерпретироваться как UTF-8).
Ниже приведены такие интерфейсы. Также см. "Ошибка Юникода". Для всех этих интерфейсов Perl в настоящее время (начиная с версии 5.16.0) просто предполагает байтовые строки как для аргументов, так и для результатов, или строки UTF-8, если используется (устаревшее) директива encoding.
Одна из причин, по которой Perl не пытается определить роль Юникода в этих ситуациях, заключается в том, что ответы сильно зависят от операционной системы и файловой системы. Например, то, могут ли имена файлов быть в Юникоде и в каком именно кодировании, не является точно переносимым понятием. Точно так же для qx и system: насколько хорошо «интерфейс командной строки» (и какой из них?) будет обрабатывать Юникод?
-
chdir,chmod,chown,chroot,exec,link,lstat,mkdir,rename,rmdir,stat,symlink,truncate,unlink,utime,-X -
%ENV -
glob(также известный как<*>) -
open,opendir,sysopen -
qx(также известный как оператор обратных кавычек),system -
readdir,readlink
Ошибка «Юникода»
Термин «ошибка Юникода» был применён к несоответствию кодовых точек в блоке Latin-1 Supplement, то есть между 128 и 255. Без указанной локали, в отличие от всех других символов или кодовых точек, эти символы могут иметь очень разные семантики в зависимости от действующих правил. (Символы, кодовые точки которых находятся выше 255, вынуждают использовать правила Юникода; в то время как правила для символов ASCII одинаковы как при правилах ASCII, так и Юникода.)
В соответствии с правилами Юникода эти символы верхнего латинского 1 интерпретируются как кодовые точки Юникода, что означает, что они имеют одинаковую семантику с латинским 1 (ISO-8859-1) и C1-управляющими символами.
Как объясняется в "Правила ASCII против правил Юникода", по правилам ASCII, они считаются неназначенными символами.
Это может привести к непредвиденным результатам. Например, семантика строки может внезапно измениться, если к ней добавить кодовую точку выше 255, что меняет правила с ASCII на Юникод. В качестве примера рассмотрим следующую программу и её вывод:
$ 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 не нарушать старые программы, не использующие Юникод, а также желанием Perl добавить поддержку Юникода безболезненно. Но результат получился не безболезненным. (Кстати, вы можете выбрать получать предупреждения, когда происходят подобные события. См. encoding::warnings.)
use feature 'unicode_strings' был добавлен, начиная с Perl v5.12, для решения этой проблемы. Он влияет на следующие моменты:
-
Изменение регистра скаляра, то есть использование
uc(),ucfirst(),lc(),lcfirst(), или\L,\U,\uи\lв контекстах двойных кавычек, таких как подстановки в регулярных выражениях.В соответствии с
unicode_strings, начиная с Perl 5.12.0, в основном используются правила Юникода. Подробности о работе с различными другими директивами см. в "lc" в perlfunc. -
Использование сопоставления с безразличием к регистру (
/i) в регулярных выражениях.Начиная с Perl 5.14.0, регулярные выражения, скомпилированные в пределах области действия
unicode_strings, используют правила Юникода даже при выполнении или компиляции в более крупные регулярные выражения вне этой области. -
Сопоставление любых нескольких свойств в регулярных выражениях.
Эти свойства:
\b(без фигурных скобок),\B(без фигурных скобок),\s,\S,\w,\W, и все классы символов Posix, кроме[[:ascii:]].Начиная с Perl 5.14.0, регулярные выражения, скомпилированные в пределах области действия
unicode_strings, используют правила Юникода даже при выполнении или компиляции в более крупные регулярные выражения вне этой области. -
В
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. До этого или вне этой области символы, являющиеся пробельными в соответствии с правилами Юникода, но не в соответствии с правилами ASCII, обрабатывались как содержимое поля, а не разделители полей, когда они встречались в байтовых кодированных строках.
Из вышесказанного видно, что влияние unicode_strings увеличивалось с несколькими выпусками Perl. (И поддержка Юникода в Perl продолжает улучшаться; лучше использовать последнюю доступную версию, чтобы получить наиболее полные и точные результаты.) Обратите внимание, что unicode_strings автоматически выбирается, если у вас есть use v5.12 или более поздняя версия.
Для версий Perl, более ранних, чем описанные выше, или когда строка передаётся функции вне области действия unicode_strings, см. следующий раздел.
Принудительное использование Юникода в Perl (или отключение Юникода в Perl)
Иногда (см. "Когда Юникод не используется" или "Ошибка Юникода") бывают ситуации, когда вам просто нужно принудительно преобразовать байтовую строку в UTF-8 или наоборот. Для этого можно использовать стандартный модуль Encode, или низкоуровневые функции utf8::upgrade($bytestring) и utf8::downgrade($utf8string[, FAIL_OK]).
Обратите внимание, что utf8::downgrade() может завершиться неудачей, если строка содержит символы, которые не помещаются в один байт.
Вызов любой из этих функций для строки, которая уже находится в желаемом состоянии, является пустой операцией.
"Правила ASCII против правил Юникода" описывает все способы, которыми строка принуждается к использованию правил Юникода.
Использование Юникода в XS
См. "Поддержка Юникода" в perlguts для введения в Юникод на уровне XS и "Поддержка Юникода" в perlapi для получения информации об API.
Модификация Perl для работы с более ранними версиями Юникода (только для очень серьёзных хаккеров)
Perl по умолчанию поставляется с последней поддерживаемой версией Юникода, но цель состоит в том, чтобы дать возможность изменить её на любую более раннюю версию. Однако в Perl v5.20 и v5.22 самая ранняя используемая версия — Юникод 5.1. Perl v5.18 и v5.24 способны обрабатывать все более ранние версии.
Загрузите файлы нужной версии Юникода с веб-сайта Unicode https://www.unicode.org). Они должны заменить существующие файлы в lib/unicore в дереве исходных кодов Perl. Следуйте инструкциям в файле README.perl в этом каталоге, чтобы изменить некоторые из их имён, а затем скомпилируйте Perl (см. INSTALL).
Перевод кода из perl-5.6.X
Начиная с версии 5.8, в Perl используется другая модель Юникода, чем в версии 5.6. В версии 5.6 программисту требовалось использовать директиву utf8, чтобы объявить, что данный участок кода ожидает работу с данными Юникода, и нужно было убедиться, что в этот участок кода попадают только данные Юникода. Если у вас есть код, работающий с версией 5.6, вам понадобятся некоторые из следующих корректировок в вашем коде. Примеры написаны так, чтобы код продолжал работать в версии 5.6, поэтому вы можете смело их попробовать.
-
Дескриптор файла, который должен читать или записывать UTF-8
if ($] > 5.008) { binmode $fh, ":encoding(UTF-8)"; } -
Скаляр, который будет передан в какое-либо расширение
Будет ли это
Compress::Zlib,Apache::Requestили любое расширение, в котором нет упоминания о Юникоде в справке, вам необходимо убедиться, что флаг 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;
ОШИБКИ
См. также "Ошибка Юникода" выше.
Взаимодействие с расширениями
Когда Perl обменивается данными с расширением, расширение должно уметь понимать флаг UTF8 и действовать соответствующим образом. Если расширение не распознает этот флаг, вероятно, оно вернёт данные с неправильным флагом.
Поэтому, если вы работаете с данными Юникода, проконсультируйтесь с документацией каждого используемого модуля, чтобы узнать, есть ли какие-либо проблемы с обменом данными Юникода. Если в документации вообще ничего не сказано об Юникоде, предполагайте худшее и, вероятно, изучите исходный код, чтобы понять, как модуль реализован. Модули, написанные полностью на Perl, не должны вызывать проблем. Модули, которые напрямую или косвенно обращаются к коду, написанному на других языках программирования, находятся под риском.
Для затронутых функций простая стратегия для предотвращения повреждения данных заключается в том, чтобы всегда явно указывать кодировку обмениваемых данных. Выберите кодировку, которую расширение может обработать. Преобразуйте аргументы, передаваемые расширению, в эту кодировку, и преобразуйте результаты обратно из этой кодировки. Напишите оберточные функции, которые выполняют преобразования за вас, чтобы вы могли впоследствии изменить эти функции, когда расширение будет поддерживать нужные функции.
Давайте рассмотрим пример, допустим, популярная Foo::Bar::escape_html функция ещё не обрабатывает данные Юникода. Функция-обёртка преобразует аргумент в чистый 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 и аналогичные. Обращайте внимание на такие фильтры в документации ваших расширений; они могут значительно упростить переход к данным Юникода.
Скорость
Некоторые функции работают медленнее при работе со строками, закодированными в UTF-8, чем со строками, закодированными в байтах. Все функции, которым необходимо переходить по символам, такие как length(), substr() или index(), или сопоставлять регулярные выражения, могут работать намного быстрее, когда исходные данные закодированы в байтах.
В Perl 5.8.0 эта медлительность часто была весьма заметной; в Perl 5.8.1 была введена схема кэширования, которая улучшила ситуацию. В целом, операции со строками, закодированными в UTF-8, всё ещё медленнее. Например, свойства Юникода (классы символов), такие как \p{Nd}, известны тем, что они работают значительно медленнее (в 5-20 раз) по сравнению со своими более простыми аналогами, такими как [0-9] (хотя опять же, существует сотни символов Юникода, соответствующих Nd, по сравнению с 10 символами ASCII, соответствующих [0-9]).
СМОТРИТЕ ТАКЖЕ
perlunitut, perluniintro, perluniprops, Encode, open, utf8, bytes, perlretut, "${^UNICODE}" в perlvar, https://www.unicode.org/reports/tr44).
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/perlunicode