Unicode – это набор символов, целью которого является определение всех символов и глифов всех человеческих языков, живых и мертвых. Поскольку всё больше и больше программ должны поддерживать несколько языков или просто любой язык, юникод в последние годы приобретает всё большую популярность. Использование различных наборов символов для разных языков может быть слишком обременительным для программистов и пользователей.
К сожалению, юникод привносит свои требования и подводные камни, когда речь заходит о регулярных выражениях. Из всех движков регулярных выражений, обсуждаемых здесь, Java, XML и .NET используют движки поддерживающие юникод. Perl поддерживает юникод, начиная с версии 5.6. будет соответствовать как однокодовому, так и двухкодовому варианту à
, в то время как Pattern.compile("\\u00E0")
соответствует только однокодовой версии. Помните, что при записи regex как строкового литерала Java, обратные слэши должны быть экранированы. Первый код Java компилирует regex à
, а второй компилирует \u00E0. В зависимости от того, что вы делаете, разница может быть существенной.
JavaScript, который не предлагает никакой поддержки Unicode через свой класс RegExp, поддерживает \uFFFF
для соответствия одному коду.
XML Schema и XPath не имеют regex токенов для сопоставления кодов Unicode. Однако вы можете легко использовать такие XML-сущности, как 
для вставки явных кодов в ваше регулярное выражение.
Категории в Юникоде
В дополнение к сложностям, Unicode также приносит и новые возможности. Одна из них заключается в том, что каждый символ юникода принадлежит к определенной категории. Вы можете сопоставить один символ, принадлежащий к категории «буква», с \p{L}
, или не принадлежащий к ней, с \P{L}
.
Опять же, «символ» на самом деле означает «код юникод-символа». \p{L}
соответствует одному коду в категории «буква». Если входная строка à
закодирована как U+0061 U+0300
, она соответствует a
без грависа. Если входная строка à
закодирована как U+00E0
, она соответствует à
с грависом. Причина в том, что коды U+0061
(a) и U+00E0
(à) относятся к категории «буква», а U+0300
– к категории «знак».
Теперь вы должны понять, почему Perl и JGsoft позволяют использовать Java 7 добавляет поддержку категорий письменностей. В отличие от прочих, Java 7 требует префикс Стандарт Unicode делит карту символов на различные блоки или диапазоны кодов. Каждый блок используется для определения символов конкретной письменности, например, «тибетское письмо» или относящихся к определенной группе, например, «шрифт Брайля». Большинство блоков включают нераспределённые коды, зарезервированные для будущего расширения стандарта. Обратите внимание, что блоки юникода не совпадают на 100% с категориями письменностей. Существенное различие между блоками и данными категориями заключается в том, что блок – это один непрерывный диапазон кодов, как указано ниже. Категории письменностей состоят из символов, взятых со всей карты символов юникода. Блоки могут включать неназначенные коды (т.е. коды, соответствующие Например, блок Не все regex-движки с поддержкой юникода используют одинаковый синтаксис для сопоставления блоков. Java, Ruby 2.0 и XRegExp используют синтаксис В .NET и XML вы должны опустить подчёркивание, но сохранить дефисы в именах блоков. Например, используйте Фактические имена блоков одинаковы во всех движках регулярных выражений. Имена блоков определены в стандарте Unicode. PCRE и PHP не поддерживают блоки, хотя они поддерживают категории письменностей. Хотя вы всегда должны помнить о подводных камнях, создаваемых различными способами кодирования комбинированных символов, вам не всегда нужно беспокоиться об этом. Если вы знаете, что ваша входная строка и ваше регулярное выражение используют один и тот же подход, то вам вообще не нужно беспокоиться об этом. Этот процесс называется нормализацией Unicode. Все языки программирования со встроенной поддержкой Unicode, такие как Java, C# и VB.NET, имеют функции библиотек для нормализации строк. Если вы нормализуете и объект, и регулярное выражение перед попыткой сопоставления, никаких несоответствий не возникнет. Если вы используете Java, вы можете передать флаг Если набрать на клавиатуре клавишу Наконец, если вы используете PowerGREP для поиска в текстовых файлах, закодированных с помощью традиционной кодовой страницы Windows (часто называемой «ANSI») или ISO-8859, PowerGREP всегда использует подстановку один к одному. Поскольку все кодовые страницы Windows или ISO-8859 представляют комбинированные символы одним кодом, почти все программы используют один код для каждого символа при преобразовании файла в юникод. Нашли опечатку или неточность в переводе? Выделите и нажмите \P{M}\p{M}*+
эквивалентно \X
. \P{M}
соответствует коду, который не является комбинируемым знаком, в то время как \p{M}*+
соответствует нулю или более кодов, которые являются комбинируемыми. Чтобы найти букву, включая все диакритические знаки, используйте \p{L}\p{M}*+
. Последний regex всегда будет соответствовать à
, независимо от того, как это закодировано.
\p{Common}
\p{Arabic}
\p{Armenian}
\p{Bengali}
\p{Bopomofo}
\p{Braille}
\p{Buhid}
\p{Canadian_Aboriginal}
\p{Cherokee}
\p{Cyrillic}
\p{Devanagari}
\p{Ethiopic}
\p{Georgian}
\p{Greek}
\p{Gujarati}
\p{Gurmukhi}
\p{Han}
\p{Hangul}
\p{Hanunoo}
\p{Hebrew}
\p{Hiragana}
\p{Inherited}
\p{Kannada}
\p{Katakana}
\p{Khmer}
\p{Lao}
\p{Latin}
\p{Limbu}
\p{Malayalam}
\p{Mongolian}
\p{Myanmar}
\p{Ogham}
\p{Oriya}
\p{Runic}
\p{Sinhala}
\p{Syriac}
\p{Tagalog}
\p{Tagbanwa}
\p{TaiLe}
\p{Tamil}
\p{Telugu}
\p{Thaana}
\p{Thai}
\p{Tibetan}
\p{Yi}
\p{IsLatin}
вместо \p{Latin}
. Синтаксис Is
полезен для различения письменностей и блоков, как объясняется в следующем разделе. PCRE, PHP и XRegExp не поддерживают префикс Is
.Is
.Блоки Юникода
\p{Cn}
). Категории письменностей никогда не включают неназначенные коды. Обычно, если вы не уверены, использовать ли категорию письменности или блок юникода, используйте категорию письменности.Currency
не включает символы доллара и йены. Вместо этого они находятся в блоках Basic_Latin
и Latin-1_Supplement
, несмотря на то, что оба символа являются валютными, а символ йены не является латинским символом. Это объясняется историческими причинами, поскольку стандарт ASCII включает знак доллара, а стандарт ISO-8859 – знак йены. Не следует слепо использовать любой из перечисленных ниже блоков, основываясь на их названиях. Вместо этого посмотрите на диапазоны символов, которым они фактически соответствуют. В этом может помочь такой инструмент, как RegexBuddy. Категория \p{Sc}
или \p{Currency_Symbol}
будет лучшим выбором, чем блок \p{InCurrency_Symbols}
, когда вы пытаетесь найти все символы валюты.Блоки юникода
\p{InBasic_Latin}: U+0000–U+007F
\p{InLatin-1_Supplement}: U+0080–U+00FF
\p{InLatin_Extended-A}: U+0100–U+017F
\p{InLatin_Extended-B}: U+0180–U+024F
\p{InIPA_Extensions}: U+0250–U+02AF
\p{InSpacing_Modifier_Letters}: U+02B0–U+02FF
\p{InCombining_Diacritical_Marks}: U+0300–U+036F
\p{InGreek_and_Coptic}: U+0370–U+03FF
\p{InCyrillic}: U+0400–U+04FF
\p{InCyrillic_Supplementary}: U+0500–U+052F
\p{InArmenian}: U+0530–U+058F
\p{InHebrew}: U+0590–U+05FF
\p{InArabic}: U+0600–U+06FF
\p{InSyriac}: U+0700–U+074F
\p{InThaana}: U+0780–U+07BF
\p{InDevanagari}: U+0900–U+097F
\p{InBengali}: U+0980–U+09FF
\p{InGurmukhi}: U+0A00–U+0A7F
\p{InGujarati}: U+0A80–U+0AFF
\p{InOriya}: U+0B00–U+0B7F
\p{InTamil}: U+0B80–U+0BFF
\p{InTelugu}: U+0C00–U+0C7F
\p{InKannada}: U+0C80–U+0CFF
\p{InMalayalam}: U+0D00–U+0D7F
\p{InSinhala}: U+0D80–U+0DFF
\p{InThai}: U+0E00–U+0E7F
\p{InLao}: U+0E80–U+0EFF
\p{InTibetan}: U+0F00–U+0FFF
\p{InMyanmar}: U+1000–U+109F
\p{InGeorgian}: U+10A0–U+10FF
\p{InHangul_Jamo}: U+1100–U+11FF
\p{InEthiopic}: U+1200–U+137F
\p{InCherokee}: U+13A0–U+13FF
\p{InUnified_Canadian_Aboriginal_Syllabics}: U+1400–U+167F
\p{InOgham}: U+1680–U+169F
\p{InRunic}: U+16A0–U+16FF
\p{InTagalog}: U+1700–U+171F
\p{InHanunoo}: U+1720–U+173F
\p{InBuhid}: U+1740–U+175F
\p{InTagbanwa}: U+1760–U+177F
\p{InKhmer}: U+1780–U+17FF
\p{InMongolian}: U+1800–U+18AF
\p{InLimbu}: U+1900–U+194F
\p{InTai_Le}: U+1950–U+197F
\p{InKhmer_Symbols}: U+19E0–U+19FF
\p{InPhonetic_Extensions}: U+1D00–U+1D7F
\p{InLatin_Extended_Additional}: U+1E00–U+1EFF
\p{InGreek_Extended}: U+1F00–U+1FFF
\p{InGeneral_Punctuation}: U+2000–U+206F
\p{InSuperscripts_and_Subscripts}: U+2070–U+209F
\p{InCurrency_Symbols}: U+20A0–U+20CF
\p{InCombining_Diacritical_Marks_for_Symbols}: U+20D0–U+20FF
\p{InLetterlike_Symbols}: U+2100–U+214F
\p{InNumber_Forms}: U+2150–U+218F
\p{InArrows}: U+2190–U+21FF
\p{InMathematical_Operators}: U+2200–U+22FF
\p{InMiscellaneous_Technical}: U+2300–U+23FF
\p{InControl_Pictures}: U+2400–U+243F
\p{InOptical_Character_Recognition}: U+2440–U+245F
\p{InEnclosed_Alphanumerics}: U+2460–U+24FF
\p{InBox_Drawing}: U+2500–U+257F
\p{InBlock_Elements}: U+2580–U+259F
\p{InGeometric_Shapes}: U+25A0–U+25FF
\p{InMiscellaneous_Symbols}: U+2600–U+26FF
\p{InDingbats}: U+2700–U+27BF
\p{InMiscellaneous_Mathematical_Symbols-A}: U+27C0–U+27EF
\p{InSupplemental_Arrows-A}: U+27F0–U+27FF
\p{InBraille_Patterns}: U+2800–U+28FF
\p{InSupplemental_Arrows-B}: U+2900–U+297F
\p{InMiscellaneous_Mathematical_Symbols-B}: U+2980–U+29FF
\p{InSupplemental_Mathematical_Operators}: U+2A00–U+2AFF
\p{InMiscellaneous_Symbols_and_Arrows}: U+2B00–U+2BFF
\p{InCJK_Radicals_Supplement}: U+2E80–U+2EFF
\p{InKangxi_Radicals}: U+2F00–U+2FDF
\p{InIdeographic_Description_Characters}: U+2FF0–U+2FFF
\p{InCJK_Symbols_and_Punctuation}: U+3000–U+303F
\p{InHiragana}: U+3040–U+309F
\p{InKatakana}: U+30A0–U+30FF
\p{InBopomofo}: U+3100–U+312F
\p{InHangul_Compatibility_Jamo}: U+3130–U+318F
\p{InKanbun}: U+3190–U+319F
\p{InBopomofo_Extended}: U+31A0–U+31BF
\p{InKatakana_Phonetic_Extensions}: U+31F0–U+31FF
\p{InEnclosed_CJK_Letters_and_Months}: U+3200–U+32FF
\p{InCJK_Compatibility}: U+3300–U+33FF
\p{InCJK_Unified_Ideographs_Extension_A}: U+3400–U+4DBF
\p{InYijing_Hexagram_Symbols}: U+4DC0–U+4DFF
\p{InCJK_Unified_Ideographs}: U+4E00–U+9FFF
\p{InYi_Syllables}: U+A000–U+A48F
\p{InYi_Radicals}: U+A490–U+A4CF
\p{InHangul_Syllables}: U+AC00–U+D7AF
\p{InHigh_Surrogates}: U+D800–U+DB7F
\p{InHigh_Private_Use_Surrogates}: U+DB80–U+DBFF
\p{InLow_Surrogates}: U+DC00–U+DFFF
\p{InPrivate_Use_Area}: U+E000–U+F8FF
\p{InCJK_Compatibility_Ideographs}: U+F900–U+FAFF
\p{InAlphabetic_Presentation_Forms}: U+FB00–U+FB4F
\p{InArabic_Presentation_Forms-A}: U+FB50–U+FDFF
\p{InVariation_Selectors}: U+FE00–U+FE0F
\p{InCombining_Half_Marks}: U+FE20–U+FE2F
\p{InCJK_Compatibility_Forms}: U+FE30–U+FE4F
\p{InSmall_Form_Variants}: U+FE50–U+FE6F
\p{InArabic_Presentation_Forms-B}: U+FE70–U+FEFF
\p{InHalfwidth_and_Fullwidth_Forms}: U+FF00–U+FFEF
\p{InSpecials}: U+FFF0–U+FFFF
\p{InBlock}
, как указано выше. В .NET и XML вместо этого используется \p{IsBlock}
. Perl и JGsoft поддерживают обе нотации. Рекомендуется использовать нотацию In
, если ваш regex-движок поддерживает её. In
можно использовать только для блоков Unicode, в то время как Is
можно использовать для общих категорий и категорий письменностей, в зависимости от используемого вами шаблона регулярных выражений. При использовании In
очевидно, что вы сопоставляете блок, а не общую категорию или письменность с аналогичным названием.\p{IsLatinExtended-A}
вместо \p{InLatin_Extended-A}
. В Java вы должны опустить дефисы. .NET и XML также сравнивают имена с учетом регистра, в то время как Perl, Ruby и JGsoft сравнивают их без учета регистра. Java 4 чувствительна к регистру. Java 5 и более поздние версии учитывают регистр для префикса Is
, но не для самих имен блоков.Нужно ли вам беспокоиться о различных кодировках?
CANON_EQ
в качестве второго параметра в Pattern.compile()
. Это указывает движку регулярных выражений Java считать канонически эквивалентные символы идентичными. Символ à
, закодированный как U+00E0
, соответствует à
, закодированному как U+0061 U+0300
, и наоборот. Ни один из других regex-движков в настоящее время не поддерживает каноническую эквивалентность при сопоставлении.à
, все известные нам текстовые процессоры вставят в файл код U+00E0
. Таким образом, если вы работаете с текстом, который вы набрали сами, любое регулярное выражение, который вы набрали сами, будет соответствовать таким же образом.
CTRL/⌘+Enter
ссылка на оригинал статьи https://habr.com/ru/post/713256/
Добавить комментарий