Spec-Zone.ru › Perl 5.30

perlunicode

СОДЕРЖАНИЕ

  • ИМЯ
  • ОПИСАНИЕ
    • Важные замечания
    • Семантика байтов и символов
    • Правила ASCII по сравнению с правилами Unicode
    • Расширенные кластеры графем (логические символы)
    • Свойства символов Unicode
      • Категория
      • Типы символов с двунаправленным упорядочением
      • Шрифты
      • Использование префикса "Is"
      • Блоки
      • Другие свойства
    • Подстановочные знаки в значениях свойств
    • Пользовательские свойства символов
    • Пользовательские отображения регистров (только для серьёзных хакеров)
    • Кодировки символов для ввода и вывода
    • Уровень поддержки регулярных выражений Unicode
      • Уровень 1 — базовая поддержка Unicode
      • Уровень 2 — расширенная поддержка Unicode
      • Уровень 3 — настраиваемая поддержка
    • Кодировки 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 см. http://www.unicode.org.

Важные замечания

Даже если некоторые части этого раздела могут быть непонятны с первого прочтения, мы считаем важным выделить некоторые подводные камни, прежде чем углубляться дальше, поэтому вот:

Поддержка Unicode — это обширное требование. Хотя Perl не реализует стандарт Unicode или соответствующие технические отчеты от корки до корки, Perl поддерживает многие функции Unicode.

Кроме того, использование Unicode может создать проблемы безопасности, которые не очевидны, см. "Последствия использования Unicode для безопасности" ниже.

Безопаснее всего, если вы use feature 'unicode_strings'

Для сохранения обратной совместимости Perl не включает полную внутреннюю поддержку Unicode, если не указан псевдоним use feature 'unicode_strings'. (Это автоматически выбирается, если вы use 5.012 или выше). Отсутствие этого может вызвать неожиданные сюрпризы. См. "Ошибка 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 (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. Если вы не уверены в кодировке строки, понизьте ее уровень перед использованием любого из этих операторов; вы можете использовать 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 Transformation Format), то все строковые литералы внутри неё должны быть Unicode.

  • В области действия use feature 'unicode_strings'

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

  • В области действия use 5.012 или выше

    Это неявно включает 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» и «КОМБИНИРУЮЩИЙ ДИАКРИТИЧЕСКИЙ ЗНАК» называется каноническим эквивалентом. Все прекомпонованные символы, как говорят, имеют разложение (на эквивалентную последовательность), а тип разложения также называется каноническим. Строка может быть составлена по возможности из прекомпонованных символов или целиком из разложенных символов. Юникод называет их соответственно «Нормализованная форма составленная» (NFC) и «Нормализованная форма разложенная». Модуль Unicode::Normalize содержит функции, которые преобразуют между ними. Строка также может содержать как составные, так и разложенные символы; этот модуль можно использовать, чтобы сделать их все одним или другим.

Вы можете столкнуться со строками в любой из этих эквивалентных форм. В настоящее время в Perl 5 нет ничего, что игнорировало бы различия. Поэтому вам нужно будет специально обработать это. Обычно рекомендуется преобразовать ваши входные данные в NFD перед дальнейшей обработкой.

Для получения более подробной информации см. http://unicode.org/reports/tr15/.

Свойства символов Юникода

(Единственный случай, когда Perl рассматривает последовательность отдельных кодовых точек как один логический символ, — это в конструкции \X, уже упомянутой выше. Поэтому «символ» в этой дискуссии означает одну кодовую точку Юникода.)

Практически все свойства символов Юникода доступны через регулярные выражения с использованием конструкции \p{} «соответствует свойству» и \P{} «не соответствует свойству» для отрицания.

Например, \p{Uppercase} соответствует любому одиночному символу со свойством Юникода "Uppercase", в то время как \p{L} соответствует любому символу со свойством General_Category "L" (буква) (см. "General_Category" ниже). Скобки не требуются для имён свойств, состоящих из одной буквы, поэтому \p{L} эквивалентно \pL.

Более формально, \p{Uppercase} соответствует любому одиночному символу, значение свойства Юникода 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}.

Все свойства символов, определённые Юникодом, могут быть записаны в этих составных формах \p{property=value} или \p{property:value}, но Perl предоставляет некоторые дополнительные свойства, которые записаны только в единственной форме, а также сокращённые формы для всех двоичных свойств и некоторых других, описанных ниже, в которых вы можете опустить имя свойства и разделитель равенства или двоеточия.

У большинства свойств символов Юникода есть по крайней мере два синонима (или псевдонимы, если хотите): короткий, проще в наборе, и более длинный, более описательный, и поэтому более лёгкий для понимания. Таким образом, свойства "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} эквивалентно. Всё это Юникод называет «свободным сопоставлением». В немногих случаях используется более строгое соответствие — в середине чисел и в свойствах расширения Perl, которые начинаются или заканчиваются нижним подчёркиванием. Более строгое сопоставление учитывает пробелы (кроме пробелов рядом с небуквенными символами), дефисы и нижние подчёркивания не в начале/конце слова.

Вы также можете использовать отрицание в \p{} и \P{} с помощью символа «^» (^) между первой фигурной скобкой и именем свойства: \p{^Tamil} равно \P{Tamil}.

Практически все свойства нечувствительны к регистру. Добавление модификатора регулярного выражения /i не меняет того, что они сопоставляют. Есть два набора, которые затронуты. Первый набор — Uppercase_Letter, Lowercase_Letter, и Titlecase_Letter, все из которых сопоставляются с Cased_Letter при нечувствительном к регистру сопоставлении. И второй набор — Uppercase, Lowercase, и Titlecase, все из которых сопоставляются с Cased при нечувствительном к регистру сопоставлении. Этот набор также включает подмножества PosixUpper и PosixLower , оба из которых при нечувствительном к регистру сопоставлении сопоставляются с PosixAlpha. (Разница между этими наборами заключается в том, что некоторые вещи, такие как римские цифры, существуют и в верхнем, и в нижнем регистре, поэтому они Cased, но не считаются буквами, поэтому не являются Cased_Letter.)

См. "За пределами кодовых точек Юникода" для особых случаев, когда сопоставляют свойства Юникода с несимволами Юникода.

Общая категория

Каждый символ Юникода назначен общей категории, которая является «самой распространённой категоризацией символа» (из http://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.

Типы символов для двунаправленной записи

Поскольку разные письменности отличаются по направлению записи (например, иврит и арабский пишутся справа налево), Юникод предоставляет свойство 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", это свойство может иметь дополнительные значения, которые могут быть добавлены в будущих выпусках Юникода. Указанные выше значения составляли полный набор во многих выпусках Юникода, но другие были добавлены в версии 6.3; вы всегда можете найти текущие значения в perluniprops. И http://www.unicode.org/reports/tr9/ описывает, как их использовать.

Письменности

Языки мира написаны многими различными письменными системами. Это предложение (если вы не читаете его в переводе) написано латиницей, в то время как русский язык написан кириллицей, а греческий язык написан, ну, греческим алфавитом; японский язык в основном на иероглифах, или катакане и хирагане. Есть много других.

Свойства Юникода 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 «Свойство скрипта Unicode»: http://www.unicode.org/reports/tr24.

Полный список скриптов и их сокращений находится в perluniprops.

Использование префикса "Is"

Для обеспечения обратной совместимости (с древними Perl 5.6) все свойства, которые можно записать без использования составной формы, упомянутой до сих пор, могут иметь префикс Is или Is_, добавленный к их имени, например, \P{Is_Lu} равно \P{Lu}, а \p{IsScript:Arabic} равно \p{Arabic}.

Блоки

В дополнение к скриптам Unicode также определяет блоки символов. Разница между скриптами и блоками заключается в том, что понятие скриптов ближе к естественным языкам, а понятие блоков больше относится к искусственной группировке, основанной на группах символов Unicode с последовательными порядковыми значениями. Например, блок "Basic Latin" включает все символы, порядковые значения которых находятся в диапазоне от 0 до 127 включительно; другими словами, символы ASCII. Скрипт "Latin" содержит некоторые буквы из этого, а также несколько других блоков, таких как "Latin-1 Supplement", "Latin Extended-A", и т.д., но он не содержит все символы из этих блоков. Например, он не содержит цифр от 0 до 9, так как эти цифры общие для многих скриптов и, следовательно, находятся в скрипте Common.

Для получения дополнительной информации о скриптах и блоках см. UAX#24 «Свойство скрипта Unicode»: http://www.unicode.org/reports/tr24

Свойства Script_Extensions или Script, скорее всего, являются теми, которые вам нужно использовать при обработке естественного языка; свойство Block может быть полезно в работе с основами Unicode.

Имена блоков сопоставляются в составной форме, например \p{Block: Arrows} или \p{Blk=Hebrew}.

В отличие от большинства других свойств, только несколько имён блоков имеют определенное сокращённое имя в Unicode.

Perl также определяет синонимы для свойства блока в одиночной форме в тех случаях, когда это не конфликтует с чем-то другим. Но не используйте их, потому что они нестабильны. Поскольку это расширения Perl, они подчиняются официальным именам свойств Unicode; Unicode не знает и не заботится о расширениях Perl. Может случиться, что имя, которое сейчас означает расширение Perl, в будущем будет изменено без предупреждения, чтобы обозначать другое свойство Unicode в будущей версии интерпретатора Perl, использующего более позднюю версию Unicode, и ваш код перестанет работать. Эти расширения упоминаются здесь для полноты: возьмите имя блока и добавьте один из префиксов: In (например, \p{Blk=Arrows} в настоящее время можно записать как \p{In_Arrows}); или иногда Is (например, \p{Is_Arrows}); или иногда вообще без префикса (\p{Arrows}). На момент написания (Unicode 9.0) нет конфликтов при использовании префикса In_, но есть много конфликтов с другими двумя формами. Например, \p{Is_Hebrew} и \p{Hebrew} означают \p{Script_Extensions=Hebrew}, что НЕ то же самое, что \p{Blk=Hebrew}.

Наш совет раньше был использовать префикс In_ как способ в одиночной форме указать блок. Но Unicode 8.0 добавил свойства, имена которых начинаются с In, и теперь ясно, что это просто удача, что до сих пор не было конфликтов. Использование In лишь немного меньше, чем Blk:, а значение последнего более ясно и гарантированно никогда не будет конфликтовать. Так что не рискуйте. Используйте \p{Blk=foo} для нового кода. И убедитесь, что блок — это то, что вы действительно хотите сделать. В большинстве случаев вместо блоков нужно использовать скрипты.

Полный список блоков находится в perluniprops.

Другие свойства

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

Unicode определяет все свои свойства в составной форме, поэтому все свойства в одиночной форме являются расширениями Perl. Большинство из них — это просто синонимы для свойств Unicode, но некоторые — настоящие расширения, включая несколько, которые находятся в составной форме. И немало из них на самом деле рекомендуются Unicode (в http://www.unicode.org/reports/tr18).

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

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} (Сокр.: \p{Dt=NonCanon})

Соответствует символу, имеющему неканоническое разложение.

В разделе "Расширенные кластеры графем (логические символы)" выше говорилось о канонических разложениях. Однако многие другие символы имеют разный тип разложения, «совместимое» или «неканоническое» разложение. Последовательности, образующие эти разложения, не считаются канонически эквивалентными предварительно составленному символу. Примером является "SUPERSCRIPT ONE". Он чем-то похож на обычную цифру 1, но не совсем; его разложение на цифру 1 называется «совместимым» разложением, конкретно «супер» разложением. Существует несколько таких совместимых разложений (см. http://www.unicode.org/reports/tr44), включая одно, называемое «compat», что означает некоторый вид разложения, не подходящий под другие категории разложений, выбранные Unicode.

Обратите внимание, что у большинства символов Unicode нет разложения, поэтому тип их разложения — "None".

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

\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: *} (Сокр.: \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}). Разница в том, что при сопоставлении без учёта регистра /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 Character Classes" в perlrecharclass.

Дикие карты в значениях свойств

Начиная с 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 для указания модификаторов.

Эта функция недоступна, когда левая часть начинается с Is_, а также для любых форм, помеченных как «Не рекомендуется» в "Не рекомендуется" в perluniprops.

Perl оборачивает ваш шаблон в (?iaa: ... ). Это связано с тем, что ничего вне ASCII не может соответствовать значениям свойств Unicode, доступным в этом выпуске, и они должны соответствовать без учёта регистра. Если ваш шаблон содержит синтаксическую ошибку, эта обертка будет отображаться в сообщении об ошибке, даже если вы её не указывали. Это может быть запутанно, если вы не знаете об этом.

Эта экспериментальная функция была добавлена, чтобы начать реализовывать https://www.unicode.org/reports/tr18/#Wildcard_Properties. Её использование вызовет предупреждение (по умолчанию включено) в категории experimental::uniprop_wildcards. Мы оставляем за собой право изменить его работу по мере накопления опыта.

END_OF_DOCUMENT_MARKER

Ваш подшаблон может быть практически чем угодно, но для его полезности он должен совпадать, если вызывается с полным именем значения свойства с нижними подчеркиваниями (и/или пробелами в свойстве Блок) и некоторыми заглавными буквами; или б) значением свойства в нижнем регистре со сжатыми пробелами и подчеркиваниями. Например,

qr!\p{Blk=/Old I.*/}!
qr!\p{Blk=/oldi.*/}!

будет совпадать с теми же вещами.

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

Другой пример, показывающий, что в \p{...}, /x не нужно, чтобы были пробелы:

qr!\p{scx= /Hebrew|Greek/ }!

Для безопасности мы должны были бы закрепить вышеприведенный пример, чтобы предотвратить совпадения со чем-то вроде Hebrew_Braile, но скриптов с таким именем нет.

Существуют определённые свойства, с которыми он в настоящее время не работает. Это:

Bidi Mirroring Glyph
Bidi Paired Bracket
Case Folding
Decomposition Mapping
Equivalent Unified Ideograph
Name
Name Alias
Lowercase Mapping
NFKC Case Fold
Titlecase Mapping
Uppercase Mapping

Также не реализована форма @unicode_property@.

Вот полный пример сопоставления адресов интернет-протокола IPV4 в любом (одном) скрипте

no warnings 'experimental::script_run';
no warnings 'experimental::regex_sets';
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 предоставляет альтернативу, которая позволяет определять более сложные свойства.) Подпрограммы могут быть определены в любом пакете. Определённые пользователем свойства могут использоваться в регулярных выражениях \p{} и \P{} конструкции; если вы используете свойство, определённое пользователем из пакета, отличного от текущего, вы должны указать его пакет в \p{} или \P{} конструкции.

# assuming property Is_Foreign 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-doc находится в начале строки. Теперь вы можете использовать \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 кодовым точкам, поскольку каждая из них не входит в Kana. Вы можете использовать пересечение, чтобы исключить их, если хотите, как показано в этом изменённом примере:

sub InNotKana {
    return <<'END';
!utf8::InHiragana
-utf8::InKatakana
+utf8::IsCn
&utf8::Any
END
}

&utf8::Any должна быть последней строкой в определении.

Пересечение используется в целом для получения общих символов, соответствующих двум (или более) классам. Важно помнить, что не следует использовать "&" для первого набора; это означало бы пересечение с ничем, что привело бы к пустому набору. (Аналогично, использование "-" для первого набора ничего не даёт).

В отличие от совпадений со свойствами, не определёнными пользователем, \p{} никогда не генерируется предупреждение, если эти свойства сопоставляются с не-Unicode кодовыми точками (см. "Beyond Unicode code points" ниже).

Определяемые пользователем преобразования регистра (только для серьёзных хакеров)

Эта функция была удалена с версии 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     - Experimental  [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:], плюс все свойства, указанные по адресу http://www.unicode.org/reports/tr18/#Compatibility_Properties. Они описаны выше в разделе "Другие свойства"
[4]

Экспериментальная функция "(?[...])", начиная с версии 5.18, выполняет это.

См. "(?[ ])" в perlre. Если вы не хотите использовать экспериментальную функцию, вы можете использовать одну из следующих:

  • Проверка по регулярному выражению

    Вы можете имитировать вычитание класса с помощью проверки вперёд. Например, то, что UTS#18 может записать как

    [{Block=Greek}-[{UNASSIGNED}]]

    в Perl можно записать как:

    (?!\p{Unassigned})\p{Block=Greek}
    (?=\p{Assigned})\p{Block=Greek}

    Но в этом конкретном примере вы, вероятно, хотите

    \p{Greek}

    чтобы сопоставлялись присвоенные символы, известные как часть греческого алфавита.

  • Модуль CPAN Unicode::Regex::Set

    Он реализует полный синтаксис группирования, пересечения, объединения и удаления (вычитания) UTS#18.

  • "Пользовательские свойства символов"

    "+" для объединения, "-" для удаления (разности множеств), "&" для пересечения

[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 "Алгоритм разбиения строк Юникода". Конструктор регулярных выражений обеспечивает поведение по умолчанию, в то время как более сложный модуль обеспечивает настраиваемое разбиение строк.

Но Perl рассматривает \n как разделитель начала и конца строки, в то время как Юникод определяет больше символов, которые должны быть интерпретированы таким образом.

Это:

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 - Расширенная поддержка Юникода

RL2.1   Canonical Equivalents           - Retracted     [9]
                                          by Unicode
RL2.2   Extended Grapheme Clusters      - Partial       [10]
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                 - Done
[9] Юникод переписал эту часть UTS#18, сказав, что получение канонического эквивалента (см. UAX#15 "Нормальные формы Юникода") в основном должно выполняться на уровне программиста. Используйте NFD для записи как своих регулярных выражений, так и текста для сопоставления с ними (вы можете использовать Unicode::Normalize).
[10] Perl имеет \X и \b{gcb} , но у нас нет режима "кластера графем".
[11] см. UAX#29 "Сегментация текста Юникода",
[12] см. "Подстановки в значениях свойств" выше.

Уровень 3 - Настраиваемая поддержка

RL3.1   Tailored Punctuation            - Missing
RL3.2   Tailored Grapheme Clusters      - Missing       [13]
RL3.3   Tailored Word Boundaries        - Missing
RL3.4   Tailored Loose Matches          - Retracted by Unicode
RL3.5   Tailored Ranges                 - Retracted by Unicode
RL3.6   Context Matching                - Partial       [14]
RL3.7   Incremental Matches             - Missing
RL3.8   Unicode Set Sharing             - Retracted by Unicode
RL3.9   Possible Match Sets             - Missing
RL3.10  Folded Matching                 - Retracted by Unicode
RL3.11  Submatchers                     - Partial       [15]
[13] Perl имеет Unicode::Collate, но он не интегрирован с регулярными выражениями. См. UTS#10 "Алгоритмы сортировки Юникода".
[14] Perl имеет (?<=x) и (?=x), но это требование гласит, что должно быть возможно указать, что совпадения могут происходить только в подстроке, причём проверки вперёд и назад могут видеть за пределами этой сопоставимой части.
[15] Perl имеет пользовательские свойства ("Пользовательские свойства символов"), чтобы рассматривать отдельные кодовые точки способами, выходящими за рамки Юникода, и возможно, хотя и, вероятно, не очень чисто, использовать блоки кода и подобное (?(DEFINE)...) (см. perlre) для более специализированного сопоставления.

Кодировки Юникода

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

  • 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 (big-endian) или UTF-16LE (little-endian).

    Это создает ещё одну проблему: что делать, если известно, что данные UTF-16, но неизвестно, какой порядок байтов? Метки порядка байтов, или BOM's, — решение этой проблемы. В Unicode зарезервирован специальный символ для функции метки порядка байтов: символ с кодовой точкой U+FEFF является BOM.

    Суть в том, что если вы прочитаете BOM, вы узнаете порядок байтов, так как если он был записан на платформе big-endian, вы прочитаете байты 0xFE 0xFF, а если на платформе little-endian, вы прочитаете байты 0xFF 0xFE. (И если исходная платформа записывала в платформе ASCII UTF-8, вы прочитаете байты 0xEF 0xBB 0xBF.)

    Работает этот трюк так, что символ с кодовой точкой U+FFFE не должен быть в потоках ввода, поэтому последовательность байтов 0xFF 0xFE однозначно «BOM, представленная в формате little-endian», и не может быть U+FFFE, представленной в формате big-endian».

    Суррогаты не имеют значения в 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

    Кодировка, безопасная для семи битов (не для восьми битов), которая полезна, если транспорт или хранение не безопасны для восьми битов. Определена RFC 2152.

Непечатные кодовые точки

В Unicode 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

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

Unicode 7.0 изменил формулировку, так что они «не рекомендуются для использования в открытом обмене данными текста Unicode». В стандарте 7.0 говорится:

    "Если в открытом обмене получена непечатная кодовая точка, применение не обязано её интерпретировать каким-либо образом. Однако хорошей практикой является признание её как непечатной кодовой точки и принятие соответствующих мер, таких как замена её на U+FFFD символ замены, чтобы указать на проблему в тексте. Не рекомендуется просто удалять непечатные кодовые точки из такого текста из-за потенциальных проблем безопасности, вызванных удалением неинтерпретируемых символов. (См. положение о соответствии C7 в разделе 3.2, требования к соответствию, и Unicode Technical Report #36, "Unicode Security Considerations")."

Это изменение было внесено, потому что было обнаружено, что различные коммерческие инструменты, такие как редакторы или инструменты для системы контроля версий, были написаны так, что они не обрабатывали файлы программ, которые использовали эти кодовые точки, фактически почти полностью исключая их использование! А это никогда не было намерением. Они всегда должны были быть применимыми внутри приложения или набора взаимодействующих приложений по желанию.

Если вы пишете код, например, редактор, который должен обрабатывать любые данные текста Unicode, тогда вы не должны сами использовать эти кодовые точки, а вместо этого разрешить их ввода. Если вам нужны сигналы, они должны быть чем-то, что не является допустимым Unicode. Для данных UTF-8 вы можете использовать байты 0xC1 и 0xC2 в качестве сигналов, так как они никогда не появляются в правильно сформированном UTF-8. (Существуют эквиваленты для UTF-EBCDIC). Вы также можете хранить кодовые точки Unicode в целочисленных переменных и использовать отрицательные значения в качестве сигналов.

Если вы не пишете такой инструмент, то то, принимаете ли вы непечатные символы на входе, зависит от вас (хотя стандарт рекомендует не делать этого). Если вы делаете строгую проверку входящих потоков с помощью Perl, эти кодовые точки по-прежнему запрещены. Это делается для сохранения обратной совместимости (иначе могут возникнуть потенциальные уязвимости безопасности, поскольку неосторожное приложение, написанное с предположением, что непечатные символы будут отфильтрованы до того, как оно их получит, теперь без предупреждения может начать их получать).

Для выполнения строгой проверки можно использовать слой :encoding('UTF-8').

Perl по-прежнему будет предупреждать (используя категорию предупреждений "nonchar", которая является подкатегорией "utf8"), если будет сделана попытка вывести непечатные символы.

За пределами кодовых точек Unicode

Максимальная кодовая точка Unicode — U+10FFFF, и Unicode определяет операции только для кодовых точек до этой. Но Perl работает с кодовыми точками до максимального допустимого целого числа, доступного в платформе. Однако Perl не будет принимать их из потоков ввода, если не используются свободные правила, и будет предупреждать (используя категорию предупреждений "non_unicode", которая является подкатегорией "utf8"), если какие-либо будут выведены.

Поскольку правила Unicode не определены для этих кодовых точек, если выполняется операция, определенная Unicode, Perl использует, как мы считаем, разумные правила, при этом обычно выводит предупреждение, используя категорию "non_unicode". Например, uc("\x{11_0000}") сгенерирует такое предупреждение, вернув входной параметр в качестве результата, так как Perl определяет заглавные буквы для любой кодовой точки, не являющейся Unicode, как саму кодовую точку. (Все операции изменения регистра, а не только перевод в верхний регистр, работают таким образом.)

Ситуация с соответствием свойствам Unicode в регулярных выражениях, конструкциям \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.)

Безопасность, связанные с Юникодом

Сначала прочитайте Unicode Security Considerations.

Также обратите внимание на следующее:

  • Неправильный 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".)

Локали

См. "Юникод и 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

Если нет \w в s1 или в s2, почему их конкатенация имеет одну?

Это аномалия вызвана попыткой 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 5.012 или выше.

Для версий 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 http://www.unicode.org. Они должны заменить существующие файлы в lib/unicore в дереве исходного кода Perl. Следуйте инструкциям в файле README.perl в этом каталоге, чтобы изменить некоторые их имена, а затем скомпилируйте Perl (см. INSTALL).

Перенос кода из perl-5.6.X

В версиях Perl, начиная с 5.8, используется другая модель Юникода, чем в 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, http://www.unicode.org/reports/tr44).

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.30.3/perlunicode

Spec-Zone.ru

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