Переместиться к: allowedIn · asCapitalized · asLowerCase · asUpperCase · byCodePoint · byGrapheme · CodepointInterval · CodepointSet · codepointSetTrie · CodepointSetTrie · codepointTrie · CodepointTrie · combiningClass · compose · composeJamo · decodeGrapheme · decompose · decomposeHangul · Grapheme · graphemeStride · icmp · InversionList · isAlpha · isAlphaNum · isCodepointSet · isControl · isFormat · isGraphical · isIntegralPair · isLower · isMark · isNonCharacter · isNumber · isPrivateUse · isPunctuation · isSpace · isSurrogate · isSurrogateHi · isSurrogateLo · isSymbol · isUpper · isUtfMatcher · isWhite · lineSep · MatcherConcept · nelSep · NFC · NFD · NFKC · NFKD · NormalizationForm · normalize · paraSep · sicmp · toDelegate · toLower · toLowerInPlace · toTrie · toUpper · toUpperInPlace · unicode · UnicodeDecomposition · utfMatcher
Модуль std.uni
предоставляет реализацию базовых алгоритмов работы с Unicode и соответствующих структур данных. Он не включает в себя примитивы кодирования и декодирования UTF, для получения этих возможностей смотрите функции std.utf.decode и std.utf.encode в модуле std.utf.
Тема Unicode оказалась достаточно сложной, я в ней не являюсь экспертом, и поэтому у меня нет полной уверенности в 100% правильности этого перевода. Достаточно подробно на русском языке тема описана в этой статье: Про шрифты с продолжением. Часть 3. Также здесь: Нормализация Unicode очень наглядно показан процесс нормализации. На сайте CODEPOINTS находится база данных кодовых точек с удобной поисковой системой. Рекомендуется изучить тему по этим или аналогичным статьям, прежде чем разбираться, что делает та или иная D-функция из этого модуля – прим. пер.
Все перечисленные примитивы работают с Unicode-символами и наборами символов. Для функций, которые работают с ASCII-символами и игнорируют Unicode-символы, смотрите модуль std.ascii. Определение Unicode-символов, кодовой точки и других терминов, используемых в этом модуле, приведено ниже в разделе Терминология.
Основное внимание в этом модуле уделяется всему, что необходимо для разработки приложений, поддерживающих Unicode. С этой целью он предоставляет следующие оптимизированные примитивы:
Признаётся, что приложению могут потребоваться дополнительные усовершенствования и расширения, например менее известные алгоритмы, или адаптации существующих алгоритмов для конкретных регионов. Чтобы помочь пользователям в создании каких-либо дополнительных функций помимо основных примитивов, модуль предоставляет:
import std.uni; void main() { // Инициализация наборов кодовых точек с использованием скрипта/блока или имени свойства // теперь 'set' содержит кодовые точки обоих скриптов. auto set = unicode("Cyrillic") | unicode("Armenian"); // То же самое, но проще и проверяется во время компиляции auto ascii = unicode.ASCII; auto currency = unicode.Currency_Symbol; // простые операции с набором auto a = set & ascii; assert(a.empty); // Поскольку он не пересекается с ascii a = set | ascii; auto b = currency - a; // вычесть все ASCII, Cyrillic и Armenian //некоторые свойства наборов кодовых точек assert(b.length > 45); // 46 элементов в Unicode 6.1, ещё больше в 6.2 // проверка наличия кодовой точки в наборе // просто отлично, её сложность O(logN) assert(!b['$']); assert(!b['\u058F']); // знак армянского драма assert(b['¥']); // Построение быстрых таблиц поиска, гарантирующих сложность O(1) // 1-уровневая таблица поиска Trie по существу представляет собой огромный битовый набор ~262Kb auto oneTrie = toTrie!1(b); // 2-уровневая более компактна, но обычно немного медленнее auto twoTrie = toTrie!2(b); // 3-уровневая ещё меньше, и ещё немного медленнее auto threeTrie = toTrie!3(b); assert(oneTrie['£']); assert(twoTrie['£']); assert(threeTrie['£']); // Построить таблицу trie с самым разумным уровнем // и привязать её в качестве функтора auto cyrillicOrArmenian = toDelegate(set); auto balance = find!(cyrillicOrArmenian)("Hello ընկեր!"); assert(balance == "ընկեր!"); // совместимо с bool delegate(dchar) bool delegate(dchar) bindIt = cyrillicOrArmenian; // Нормализация string s = "Plain ascii (and not only), is always normalized!"; // Обычный ascii (и не только), всегда нормализован! assert(s is normalize(s));// та же самая строка string nonS = "A\u0308ffin"; // лигатура (соединение букв) auto nS = normalize(nonS); // в NFC - стандарт, одобренный W3C assert(nS == "Äffin"); assert(nS != nonS); string composed = "Äffin"; assert(normalize!NFD(composed) == "A\u0308ffin"); // в NFKD, декомпозицию совместимости, применяемую для нечёткого сопоставления/поиска assert(normalize!NFKD("2¹⁰") == "210"); }
Ниже приведен список важных понятий и определений Unicode. Любые соглашения, используемые специально в этом модуле, отмечены как таковые. Описания основаны на формальном определении, которое содержится в третьей главе The Unicode Standard Core Specification.
Единица информации, используемая для организации, контроля или представления текстовых данных. Обратите внимание, что:Этот модуль определяет ряд примитивов, которые работают с графемами: Grapheme, decodeGrapheme и graphemeStride. Все они используют границы расширенных графем (extended grapheme), как это описано в вышеупомянутом приложении к стандарту.
Комбинируемый символ с Общей категорией Nonspacing Mark (Mn) или Enclosing Mark (Me). Комбинируемый символ, который не является непромежуточным знаком.Тоже какие-то бюрократически бессмысленные определения, как с глифом... Как я понял по картинкам, Nonspacing Mark соотвествует всяким знакам сверху или снизу буквы, Enclosing Mark соотвествует знакам со всех сторон (вокруг) буквы, а Spacing Mark соотвествует знакам между буквами – прим.пер.
Концепции канонического эквивалента или совместимого эквивалента символов в стандарте Unicode требуют наличия полного формального определения эквивалентности для Unicode-строк. Строковая эквивалентность определяется процессом, называемым нормализацией, посредством которого строки преобразуются в формы, которые непосредственно сравниваются для идентичности. Это основная цель процесса нормализации, см. функцию normalize, предназначенную для преобразования в любую из четырёх заданных форм.
Очень важным свойством Форм Нормализации Unicode является то, что они должны оставаться стабильными между версиями стандарта Unicode. Строка Unicode, нормализованная к определенной форме нормализации Unicode в одной версии стандарта, гарантированно останется в этой Форме Нормализации в реализациях будущих версий стандарта.
В стандарте Unicode установлены четыре формы нормализации. Неформально две из этих форм определяются максимальным разложением эквивалентных последовательностей, а две из этих форм определяются максимальной компоновкой эквивалентных последовательностей.
Выбор формы нормализации зависит от конкретного варианта использования. NFC – лучшая форма для обычного текста, поскольку она более совместима со строками, преобразованными из устаревших кодировок. NFKC является предпочтительной формой для идентификаторов, особенно там, где есть проблемы с безопасностью. NFD и NFKD являются наиболее полезными для внутренней обработки.
Стандарт Unicode описывает набор алгоритмов, которые зависят от возможности быстрого поиска различных свойств кодовой точки. Учитывая, что кодовое пространство составляет около 1 миллиона кодовых точек, это не простая задача – обеспечить эффективное по использованию памяти решение для множества свойств.
Общих подходов, таких как хэш-таблицы или бинарный поиск по отсортированным интервалам кодовых точек (как в InversionList), недостаточно. Хэш-таблицы занимают огромный объём памяти, а бинарный поиск с интервалами не достаточно быстр в случае некоторых тяжелых алгоритмов.
Рекомендуемым решением (см. Unicode Implementation Guidelines) является использование многостадийных таблиц, которые представляют собой реализацию структуры данных Trie с целыми ключами и фиксированным количеством этапов. В остальной части раздела оно будет называться фиксированным trie. Ниже описывается конкретная реализация, которая нацелена на скорость доступа за счет идеальной экономии размера.
Например, для двухуровневой Trie принцип работы заключается в следующем. Разделяется количество бит в ключе (кодовой точке, состоящей из 21 бита) на 2 компонента (например, 15 и 8). Первое - это количество бит в индексе trie, а другое - количество бит на каждой странице trie. Схема trie – это массив размером 2^^бит-на-индекс, за которым следует массив блоков памяти размером 2^^бит-на-страницу/бит-на-элемент.
Количество страниц является переменным (но не менее 1) в отличие от количества записей в индексе. Все слоты индекса должны содержать те несколько страниц, которые присутствуют. Поиск - это всего лишь несколько операций - вырезать верхние биты, найти по ним индекс, взять страницу по этому индексу и использовать нижние биты в качестве смещения на этой странице.
Предполагая, что страницы расположены последовательно в одном массиве pages, вот псевдокод:auto elemsPerPage = (2 ^^ bits_per_page) / Value.sizeOfInBits;
pages[index[n >> bits_per_page]][n & (elemsPerPage - 1)];
Где, если elemsPerPage является степенью 2, весь процесс представляет собой несколько простых инструкций и 2 чтения массива. Последующие уровни trie вводятся путём рекурсии по этой идее - массив индексов рассматривается как значения. Затем количество бит в индексе снова разбивается на 2 части, со страницами над «текущим индексом» и новым «верхним индексом».
Для полноты, одноуровневая таблица trie – это просто массив. Текущая реализация использует преимущества бит-упаковки, когда известно, что диапазон ограничен заранее (например, bool). См. также BitPacked для принудительного применения его вручную. (Что-то я не нашел ничего с именем BitPacked нигде в библиотеке D – прим.пер.) Однако главное преимущество в размере происходит от того факта, что несколько одинаковых страниц на каждом уровне объединяются при строительстве.
Реальный процесс построения trie более сложен и скрыт от пользователя в виде удобных функций codepointTrie, codepointSetTrie и ещё более удобной toTrie. В общем, множество или встроенный ассоциативный массив с типом dchar можно преобразовать в trie. Объект trie в этом модуле доступен только для чтения (immutable); Он эффективно замораживается после строительства.
Это полный список свойств Юникода, доступных через структуру unicode. Обратитесь к утилите CLDR, если у вас есть сомнения относительно содержимого определенного набора.
Наборы общей категории, перечисленные ниже, доступны только с помощью сокращённого доступа через структуру unicode.
Сокр. | Длинная форма | Сокр. | Длинная форма | Сокр. | Длинная форма |
---|---|---|---|---|---|
L | Letter | Cn | Unassigned | Po | Other_Punctuation |
Ll | Lowercase_Letter | Co | Private_Use | Ps | Open_Punctuation |
Lm | Modifier_Letter | Cs | Surrogate | S | Symbol |
Lo | Other_Letter | N | Number | Sc | Currency_Symbol |
Lt | Titlecase_Letter | Nd | Decimal_Number | Sk | Modifier_Symbol |
Lu | Uppercase_Letter | Nl | Letter_Number | Sm | Math_Symbol |
M | Mark | No | Other_Number | So | Other_Symbol |
Mc | Spacing_Mark | P | Punctuation | Z | Separator |
Me | Enclosing_Mark | Pc | Connector_Punctuation | Zl | Line_Separator |
Mn | Nonspacing_Mark | Pd | Dash_Punctuation | Zp | Paragraph_Separator |
C | Other | Pe | Close_Punctuation | Zs | Space_Separator |
Cc | Control | Pf | Final_Punctuation | - | Any |
Cf | Format | Pi | Initial_Punctuation | - | ASCII |
Наборы для других общедоступных свойств, получаемых с помощью unicode:
Наименование | Наименование | Наименование |
---|---|---|
Alphabetic | Ideographic | Other_Uppercase |
ASCII_Hex_Digit | IDS_Binary_Operator | Pattern_Syntax |
Bidi_Control | ID_Start | Pattern_White_Space |
Cased | IDS_Trinary_Operator | Quotation_Mark |
Case_Ignorable | Join_Control | Radical |
Dash | Logical_Order_Exception | Soft_Dotted |
Default_Ignorable_Code_Point | Lowercase | STerm |
Deprecated | Math | Terminal_Punctuation |
Diacritic | Noncharacter_Code_Point | Unified_Ideograph |
Extender | Other_Alphabetic | Uppercase |
Grapheme_Base | Other_Default_Ignorable_Code_Point | Variation_Selector |
Grapheme_Extend | Other_Grapheme_Extend | White_Space |
Grapheme_Link | Other_ID_Continue | XID_Continue |
Hex_Digit | Other_ID_Start | XID_Start |
Hyphen | Other_Lowercase | |
ID_Continue | Other_Math |
Ниже приведена таблица с именами блоков, принимаемыми unicode.block. Обратите внимание, что в краткой версии unicode требуется добавление "In" к именам блоков, для различения сценариев и блоков.
Aegean Numbers | Ethiopic Extended | Mongolian |
Alchemical Symbols | Ethiopic Extended-A | Musical Symbols |
Alphabetic Presentation Forms | Ethiopic Supplement | Myanmar |
Ancient Greek Musical Notation | General Punctuation | Myanmar Extended-A |
Ancient Greek Numbers | Geometric Shapes | New Tai Lue |
Ancient Symbols | Georgian | NKo |
Arabic | Georgian Supplement | Number Forms |
Arabic Extended-A | Glagolitic | Ogham |
Arabic Mathematical Alphabetic Symbols | Gothic | Ol Chiki |
Arabic Presentation Forms-A | Greek and Coptic | Old Italic |
Arabic Presentation Forms-B | Greek Extended | Old Persian |
Arabic Supplement | Gujarati | Old South Arabian |
Armenian | Gurmukhi | Old Turkic |
Arrows | Halfwidth and Fullwidth Forms | Optical Character Recognition |
Avestan | Hangul Compatibility Jamo | Oriya |
Balinese | Hangul Jamo | Osmanya |
Bamum | Hangul Jamo Extended-A | Phags-pa |
Bamum Supplement | Hangul Jamo Extended-B | Phaistos Disc |
Basic Latin | Hangul Syllables | Phoenician |
Batak | Hanunoo | Phonetic Extensions |
Bengali | Hebrew | Phonetic Extensions Supplement |
Block Elements | High Private Use Surrogates | Playing Cards |
Bopomofo | High Surrogates | Private Use Area |
Bopomofo Extended | Hiragana | Rejang |
Box Drawing | Ideographic Description Characters | Rumi Numeral Symbols |
Brahmi | Imperial Aramaic | Runic |
Braille Patterns | Inscriptional Pahlavi | Samaritan |
Buginese | Inscriptional Parthian | Saurashtra |
Buhid | IPA Extensions | Sharada |
Byzantine Musical Symbols | Javanese | Shavian |
Carian | Kaithi | Sinhala |
Chakma | Kana Supplement | Small Form Variants |
Cham | Kanbun | Sora Sompeng |
Cherokee | Kangxi Radicals | Spacing Modifier Letters |
CJK Compatibility | Kannada | Specials |
CJK Compatibility Forms | Katakana | Sundanese |
CJK Compatibility Ideographs | Katakana Phonetic Extensions | Sundanese Supplement |
CJK Compatibility Ideographs Supplement | Kayah Li | Superscripts and Subscripts |
CJK Radicals Supplement | Kharoshthi | Supplemental Arrows-A |
CJK Strokes | Khmer | Supplemental Arrows-B |
CJK Symbols and Punctuation | Khmer Symbols | Supplemental Mathematical Operators |
CJK Unified Ideographs | Lao | Supplemental Punctuation |
CJK Unified Ideographs Extension A | Latin-1 Supplement | Supplementary Private Use Area-A |
CJK Unified Ideographs Extension B | Latin Extended-A | Supplementary Private Use Area-B |
CJK Unified Ideographs Extension C | Latin Extended Additional | Syloti Nagri |
CJK Unified Ideographs Extension D | Latin Extended-B | Syriac |
Combining Diacritical Marks | Latin Extended-C | Tagalog |
Combining Diacritical Marks for Symbols | Latin Extended-D | Tagbanwa |
Combining Diacritical Marks Supplement | Lepcha | Tags |
Combining Half Marks | Letterlike Symbols | Tai Le |
Common Indic Number Forms | Limbu | Tai Tham |
Control Pictures | Linear B Ideograms | Tai Viet |
Coptic | Linear B Syllabary | Tai Xuan Jing Symbols |
Counting Rod Numerals | Lisu | Takri |
Cuneiform | Low Surrogates | Tamil |
Cuneiform Numbers and Punctuation | Lycian | Telugu |
Currency Symbols | Lydian | Thaana |
Cypriot Syllabary | Mahjong Tiles | Thai |
Cyrillic | Malayalam | Tibetan |
Cyrillic Extended-A | Mandaic | Tifinagh |
Cyrillic Extended-B | Mathematical Alphanumeric Symbols | Transport And Map Symbols |
Cyrillic Supplement | Mathematical Operators | Ugaritic |
Deseret | Meetei Mayek | Unified Canadian Aboriginal Syllabics |
Devanagari | Meetei Mayek Extensions | Unified Canadian Aboriginal Syllabics Extended |
Devanagari Extended | Meroitic Cursive | Vai |
Dingbats | Meroitic Hieroglyphs | Variation Selectors |
Domino Tiles | Miao | Variation Selectors Supplement |
Egyptian Hieroglyphs | Miscellaneous Mathematical Symbols-A | Vedic Extensions |
Emoticons | Miscellaneous Mathematical Symbols-B | Vertical Forms |
Enclosed Alphanumerics | Miscellaneous Symbols | Yijing Hexagram Symbols |
Enclosed Alphanumeric Supplement | Miscellaneous Symbols and Arrows | Yi Radicals |
Enclosed CJK Letters and Months | Miscellaneous Symbols And Pictographs | Yi Syllables |
Enclosed Ideographic Supplement | Miscellaneous Technical | |
Ethiopic | Modifier Tone Letters |
Ниже приведена таблица с именами сценариев, принимаемыми unicode.script и краткой версией unicode:
Arabic | Hanunoo | Old_Italic |
Armenian | Hebrew | Old_Persian |
Avestan | Hiragana | Old_South_Arabian |
Balinese | Imperial_Aramaic | Old_Turkic |
Bamum | Inherited | Oriya |
Batak | Inscriptional_Pahlavi | Osmanya |
Bengali | Inscriptional_Parthian | Phags_Pa |
Bopomofo | Javanese | Phoenician |
Brahmi | Kaithi | Rejang |
Braille | Kannada | Runic |
Buginese | Katakana | Samaritan |
Buhid | Kayah_Li | Saurashtra |
Canadian_Aboriginal | Kharoshthi | Sharada |
Carian | Khmer | Shavian |
Chakma | Lao | Sinhala |
Cham | Latin | Sora_Sompeng |
Cherokee | Lepcha | Sundanese |
Common | Limbu | Syloti_Nagri |
Coptic | Linear_B | Syriac |
Cuneiform | Lisu | Tagalog |
Cypriot | Lycian | Tagbanwa |
Cyrillic | Lydian | Tai_Le |
Deseret | Malayalam | Tai_Tham |
Devanagari | Mandaic | Tai_Viet |
Egyptian_Hieroglyphs | Meetei_Mayek | Takri |
Ethiopic | Meroitic_Cursive | Tamil |
Georgian | Meroitic_Hieroglyphs | Telugu |
Glagolitic | Miao | Thaana |
Gothic | Mongolian | Thai |
Greek | Myanmar | Tibetan |
Gujarati | New_Tai_Lue | Tifinagh |
Gurmukhi | Nko | Ugaritic |
Han | Ogham | Vai |
Hangul | Ol_Chiki | Yi |
Ниже приведена таблица имен, принимаемая unicode.hangulSyllableType.
Сокр. | Длинная форма |
---|---|
L | Leading_Jamo |
LV | LV_Syllable |
LVT | LVT_Syllable |
T | Trailing_Jamo |
V | Vowel_Jamo |
Ссылки: ASCII Table, Wikipedia, The Unicode Consortium, Unicode normalization forms, Unicode text segmentation Unicode Implementation Guidelines Unicode Conformance
Trademarks: Unicode(tm) is a trademark of Unicode, Inc.
Исходный код: std/uni.d
lineSep
;
paraSep
;
nelSep
;
isCodepointSet
(T)isIntegralPair
(T, V = uint);
(T x){ V a = x[0]; V b = x[1];}Следующее не должно компилироваться:
(T x){ V c = x[2];}
CodepointSet
= InversionList!(GcPolicy).InversionList;
CodepointInterval
;
Переместиться к: add · byCodepoint · byInterval · empty · inverted · length · opBinary · opBinaryRight · opIndex · opOpAssign · opUnary · this · toSourceCode · toString
InversionList
(SP = GcPolicy);
InversionList
– это набор кодовых точек, представленных в виде массива с открытыми справа интервалами [a, b) (см. CodepointInterval выше). Название происходит от того, как представление читается слева направо. Например, набор всех значений [10, 50), [80, 90) плюс единичное значение 60 выглядит так:
10, 50, 60, 61, 80, 90
Способ прочитать это: начинаем с отрицательных значений, чтобы все числа, меньшие, чем следующее, отсутствовали в этом наборе (а положительные - наоборот). Затем переключаем положительный/отрицательный после каждого числа, переданного слева направо.
Таким образом, отрицательные значения находятся в диапазоне меньше 10, затем положительные до 50, затем отрицательные до 60, затем положительные до 61 и т.д. Как видно, это обеспечивает эффективное по размеру занимаемой памяти хранилище данных с высокой степенью избыточности, которые поступают в длинных партиях. Описание, для которого свойства символов Unicode прекрасно подходят. Сама методика может рассматриваться как вариация RLE-кодирования.
Наборы являются типами значений (так же, как int), таким образом, они никогда не бывают псевдонимами.
Пример:
auto a = CodepointSet('a', 'z'+1); auto b = CodepointSet('A', 'Z'+1); auto c = a; a = a | b; assert(a == CodepointSet('A', 'Z'+1, 'a', 'z'+1)); assert(a != c);
Смотрите также unicode для простого построения наборов из предустановленных.
Использование памяти – 8 байт на каждый непрерывный интервал в наборе. Семантика значения достигается с помощью метода COW, и поэтому небезопасно использовать этот тип для многопоточного использования (shared).
Замечание:
Не рекомендуется полагаться на параметры шаблона или точный тип текущего набора кодовых точек в std.uni. Тип и параметры могут измениться при завершении проектирования стандартных распределителей ресусов. Используйте isCodepointSet с шаблонами или просто придерживайтесь псевдонима по умолчанию CodepointSet на протяжении всей кодовой базы.
set
любого типа.
intervals
)intervals
.
intervals
...);
intervals
.
import std.algorithm.comparison : equal; auto set = CodepointSet('a', 'z'+1, 'а', 'я'+1); foreach (v; 'a'..'z'+1) assert(set[v]); // интервал кириллических символов нижнего регистра foreach (v; 'а'..'я'+1) assert(set[v]); // конкретный порядок не требуется, интервалы могут пересекаться auto set2 = CodepointSet('а', 'я'+1, 'a', 'd', 'b', 'z'+1); // тот же самый результат assert(set2.byInterval.equal(set.byInterval));
byInterval
();
Пример:
import std.algorithm.comparison : equal; import std.typecons : tuple; auto set = CodepointSet('A', 'D'+1, 'a', 'd'+1); assert(set.byInterval.equal([tuple('A','E'), tuple('a','e')]));
opIndex
(uint val
);
val
в этом наборе.
auto gothic = unicode.Gothic; // готическая буква ahsa assert(gothic['\U00010330']); // очевидно, ascii-символы в Gothic отсутствуют assert(!gothic['$']);
length
();
opBinary
(string op, U)(U rhs
)Устанавливает поддержку естественного синтаксиса для алгебры множеств, а именно:
Operator | Math notation | Description |
---|---|---|
& | a ∩ b | пересечение (intersection) |
| | a ∪ b | объединение (union) |
- | a ∖ b | разность (subtraction) |
~ | a ~ b | симметрическая разность (symmetric set difference), т.е. (a ∪ b) \ (a ∩ b) |
import std.algorithm.comparison : equal; import std.range : iota; auto lower = unicode.LowerCase; auto upper = unicode.UpperCase; auto ascii = unicode.ASCII; assert((lower & upper).empty); // нет пересечений auto lowerASCII = lower & ascii; assert(lowerASCII.byCodepoint.equal(iota('a', 'z'+1))); // выбросить все ASCII-символы нижнего регистра assert((ascii - lower).length == 128 - 26); auto onlyOneOf = lower ~ ascii; assert(!onlyOneOf['Δ']); // не ASCII и не нижний регистр assert(onlyOneOf['$']); // ASCII и не нижний регистр assert(!onlyOneOf['a']); // ASCII и нижний регистр assert(onlyOneOf['я']); // не ASCII, но нижний регистр // выбросить все буквы из ASCII auto noLetters = ascii - (lower | upper); assert(noLetters.length == 128 - 26*2);
opOpAssign
(string op, U)(U rhs
)opBinaryRight
(string op : "in", U)(U ch
)ch
в этом наборе, то же, что и opIndex.
assert('я' in unicode.Cyrillic); assert(!('z' in unicode.Cyrillic));
opUnary
(string op : "!")();
byCodepoint
();
import std.algorithm.comparison : equal; import std.range : iota; auto set = unicode.ASCII; set.byCodepoint.equal(iota(0, 0x80));
toString
(Writer)(scope Writer sink
, FormatSpec!char fmt
);
import std.conv : to; import std.format : format; import std.uni : unicode; assert(unicode.Cyrillic.to!string == "[1024..1157) [1159..1320) [7467..7468) [7544..7545) [11744..11776) [42560..42648) [42655..42656)"); // спецификаторы '%s' и '%d' эквивалентны показанному выше вызову to!string. assert(format("%d", unicode.Cyrillic) == unicode.Cyrillic.to!string); assert(format("%#x", unicode.Cyrillic) == "[0x400..0x485) [0x487..0x528) [0x1d2b..0x1d2c) [0x1d78..0x1d79) [0x2de0..0x2e00) " ~"[0xa640..0xa698) [0xa69f..0xa6a0)"); assert(format("%#X", unicode.Cyrillic) == "[0X400..0X485) [0X487..0X528) [0X1D2B..0X1D2C) [0X1D78..0X1D79) [0X2DE0..0X2E00) " ~"[0XA640..0XA698) [0XA69F..0XA6A0)");
add
()(uint a
, uint b
);
a
, b
) в этот набор.CodepointSet someSet; someSet.add('0', '5').add('A','Z'+1); someSet.add('5', '9'+1); assert(someSet['0']); assert(someSet['5']); assert(someSet['9']); assert(someSet['Z']);
inverted
();
auto set = unicode.ASCII; // Объединение с инверсией даст все кодовые точки в Unicode assert((set | set.inverted).length == 0x110000); // нет пересечений с инверсией assert((set & set.inverted).empty);
toSourceCode
(string funcName
= "");
funcName
, принимающей один аргумент типа dchar. Если funcName
пусто, код формируется в виде лямбда-функции.
Замечание: Используйте с осторожностью для относительно небольших или стандартных наборов. Это может быть медленнее, чем просто использование многоэтапных таблиц.
Пример:
import std.stdio; // Построить набор непосредственно из интервалов [a, b) auto set = CodepointSet(10, 12, 45, 65, 100, 200); writeln(set); writeln(set.toSourceCode("func"));Показанный пример выдаст что-то вроде:
bool func(dchar ch) @safe pure nothrow @nogc { if (ch < 45) { if (ch == 10 || ch == 11) return true; return false; } else if (ch < 65) return true; else { if (ch < 100) return false; if (ch < 200) return true; return false; } }
empty
();
CodepointSet emptySet; assert(emptySet.length == 0); assert(emptySet.empty);
codepointSetTrie
(sizes...) if (sumOfIntegerTuple!sizes == 21)Замечание: Сумма sizes должна быть равна 21.
Пример:
{ import std.stdio; auto set = unicode("Number"); auto trie = codepointSetTrie!(8, 5, 8)(set); writeln("Input code points to test:"); // Вводите кодовые точки для проверки foreach (line; stdin.byLine) { int count=0; foreach (dchar ch; line) if (trie[ch])// является ли числом count++; writefln("Contains %d number code points.", count); // Содержит count числовых кодовых точек } }
CodepointSetTrie
(sizes...) if (sumOfIntegerTuple!sizes == 21)codepointTrie
(T, sizes...) if (sumOfIntegerTuple!sizes == 21)Замечание: Перегрузка с помощью наборов CodepointSet, естественно, будет конвертировать только в таблицы Trie, отображающие в bool.
CodepointTrie
(T, sizes...) if (sumOfIntegerTuple!sizes == 21)Замечание: Только для иллюстрации, вызов любого из этих методов приведёт к ошибке утверждения (assertion failure). Используйте utfMatcher для получения конкретного matcher для кодировок UTF-8 или UTF-16.
match
(Range)(ref Range inp
)skip
(Range)(ref Range inp
)test
(Range)(ref Range inp
)
Выполняет семантический эквивалент двух операций: декодирование кодовой точки спереди inp
и проверка, принадлежит ли она к набору кодовых точек этого matcher.
Воздействие на inp
зависит от вида вызванной функции:
Match.
Если кодовая точка найдена в наборе, то диапазон inp
продвигается на её размер в кодовых блоках, в противном случае диапазон не модифицируется.
Skip. Диапазон всегда продвигается на размер проверенной кодовой точки независимо от результата проверки.
Test. Диапазон остаётся неизменным независимо от результата проверки.
string truth = "2² = 4"; auto m = utfMatcher!char(unicode.Number); assert(m.match(truth)); // '2' - это число, всё в порядке assert(truth == "² = 4"); // продвижение после match assert(m.match(truth)); // так как это надстрочный индекс '2' assert(!m.match(truth)); // пробел не является числом assert(truth == " = 4"); // не влияет при отрицательном результате match assert(!m.skip(truth)); // та же проверка ... assert(truth == "= 4"); // но независимо от результата пропускает кодовую точку assert(!m.test(truth)); // '=' не является числом assert(truth == "= 4"); // test никогда не влияет на аргумент
subMatcher
(Lengths...)();
auto m = utfMatcher!char(unicode.Number); string square = "2²"; // about sub-matchers assert(!m.subMatcher!(2,3,4).test(square)); // ASCII не подходит assert(m.subMatcher!1.match(square)); // только ASCII, работает assert(!m.subMatcher!1.test(square)); // unicode '²' assert(m.subMatcher!(2,3,4).match(square)); // assert(square == ""); wstring wsquare = "2²"; auto m16 = utfMatcher!wchar(unicode.Number); // Можно сохранить ссылку, но исходный matcher (m16) должен существовать auto bmp = m16.subMatcher!1; assert(bmp.match(wsquare)); // Подходит, т.к. присутствует в базовом многоязычном плане assert(bmp.match(wsquare)); // И '²' тоже
isUtfMatcher
(M, C);
utfMatcher
(Char, Set)(Set set
)set
, который использует Char в качестве кодового блока.
toTrie
(size_t level, Set)(Set set
)set
.
Уровень 1 самый быстрый и самый прожорливый по памяти (битовый массив).
Уровень 4 является самым медленным и занимает меньше всего места.
Смотрите раздел Краткий обзор для примера.Замечание:
Уровень 4 остаётся очень практичным (быстрее и более предсказуем) по сравнению с использованием прямого поиска на самом наборе set
.
toDelegate
(Set)(Set set
)Создаёт таблицу Trie с в основном оптимальным компромиссом скорость-размер, и заворачивает её в делегат следующего типа: bool delegate(dchar ch).
Эффективно для создания «лямбда-тестеров», подходящих для алгоритмов вроде std.algorithm.find, принимающих унарные предикаты.
Смотрите раздел Краткий обзор для примера.opDispatch
(string name)();
opCall
(C)(in C[] name
)name
не известно заранее; в противном случае, вариант времени компиляции opDispatch, как правило, лучший выбор.
block
;
Замечание:
Здесь имена блоков
недвусмысленны, поскольку нет поиска сценариев, и, следовательно, для поиска используется просто unicode.block.BlockName.
Here block
names are unambiguous as no scripts are searched
and thus to search use simply unicode.block
.BlockName notation.
// используем .block для ясности assert(unicode.block.Greek_and_Coptic == unicode.InGreek_and_Coptic);
script
;
auto arabicScript = unicode.script.arabic; auto arabicBlock = unicode.block.arabic; // Существуют пересечения между скриптом и блоком assert(arabicBlock['']); assert(arabicScript['']); // Но они различны assert(arabicBlock != arabicScript); assert(arabicBlock == unicode.inArabic); assert(arabicScript == unicode.arabic);
hangulSyllableType
;
// L здесь - это тип слога, а не буква в Юникоде. L - это сокращение auto leadingVowel = unicode.hangulSyllableType("L"); // Убеждаемся, что присутствуют некоторые ведущие гласные foreach (vowel; '\u1110'..'\u115F') assert(leadingVowel[vowel]); assert(leadingVowel == unicode.hangulSyllableType.L);
graphemeStride
(C)(in C[] input
, size_t index
)index
. Как конечная длина, так и индекс измеряются в кодовых блоках.
C | тип, неявно преобразуемый в dchars |
C[] input |
массив графемных кластеров |
size_t index |
стартовый индекс в массиве input [] |
assert(graphemeStride(" ", 1) == 1); // A + кольцо сверху string city = "A\u030Arhus"; size_t first = graphemeStride(city, 0); assert(first == 3); //\u030A состоит из 2 кодовых блоков UTF-8 assert(city[0..first] == "A\u030A"); assert(city[first..$] == "rhus");
decodeGrapheme
(Input)(ref Input inp
)inp
с типом dchar.
Замечание:
Эта функция изменяет inp
и, следовательно, inp
должен быть L-значением.
byGrapheme
(Range)(Range range
)Итерирует строку по графемам.
Полезно для выполнения манипуляций над строками, в которых требуется информация о графемах.
import std.algorithm.comparison : equal; import std.range : take, drop; import std.range.primitives : walkLength; auto text = "noe\u0308l"; // noël использует e + комбинируемый diaeresis assert(text.walkLength == 5); // 5 кодовых точек auto gText = text.byGrapheme; assert(gText.walkLength == 4); // 4 графемы assert(gText.take(3).equal("noe\u0308".byGrapheme)); assert(gText.drop(3).equal("l".byGrapheme));
byCodePoint
(Range)(Range range
)byCodePoint
(Range)(Range range
)Лениво преобразует диапазон графем в диапазон кодовых точек.
Полезно для преобразования результата в строку после выполнения операций над графемами.
Действует как тождественная функция при получении диапазона кодовых точек.
import std.array : array; import std.conv : text; import std.range : retro; string s = "noe\u0308l"; // noël // перевернуть это и преобразовать результат в строку string reverse = s.byGrapheme .array .retro .byCodePoint .text; assert(reverse == "le\u0308on"); // lëon
Переместиться к: length · opIndex · opIndexAssign · opOpAssign · opSlice · this · valid
Grapheme
;
Структура, предназначенная для эффективной упаковки символов графемного кластера.
Grapheme
имеет семантику значений, поэтому две копии Grapheme
всегда относятся к отдельным объектам. В большинстве реальных сценариев Grapheme
подходит для стека и позволяет избежать накладных расходов распределения памяти для любых, довольно длинных кластеров.
chars
...)seq
)opIndex
(size_t index
);
index
в этом кластере.
opIndexAssign
(dchar ch
, size_t index
);
ch
по заданному индексу в этот кластер.
Предупреждение: Использование этого оператора может привести кластер графем в некорректное состояние, см. также Grapheme.valid.
auto g = Grapheme("A\u0302"); assert(g[0] == 'A'); assert(g.valid); g[1] = '~'; // ASCII-тильда не является комбинируемым знаком assert(g[1] == '~'); assert(!g.valid);
opSlice
(size_t a
, size_t b
);
opSlice
();
Предупреждение: Становится недействительным, когда эта графема покидает область видимости, после этого попытки использовать этот диапазон приведут к повреждению памяти.
length
();
ch
в эту графему.
Предупреждение: Использование этого оператора может привести кластер графем в некорректное состояние, см. также Grapheme.valid.
import std.algorithm.comparison : equal; auto g = Grapheme("A"); assert(g.valid); g ~= '\u0301'; assert(g[].equal("A\u0301")); assert(g.valid); g ~= "B"; // теперь это недействительный кластер графем assert(!g.valid); // хотя, всё ещё может быть полезным assert(g[].equal("A\u0301B"));
opOpAssign
(string op, Input)(Input inp
)inp
в эту графему.
valid
()();
sicmp
(S1, S2)(S1 str1
, S2 str2
)
Выполняет тривиальное нечувствительное к регистру сравнение строк str1
и str2
. Эта функция использует более простое правило сравнения, таким образом обеспечивая лучшую производительность, чем icmp. Однако имейте в виду предупреждение ниже.
S1 str1 |
строка |
S2 str2 |
строка |
str1
лексикографически «меньше», чем str2
,> 0, если str1
лексикографически «больше», чем str2
Предупреждение: Эта функция обрабатывает отображение кодовых точек только 1:1 и, следовательно, не является достаточной для определённых алфавитов, таких как немецкий, греческий и некоторые другие.
assert(sicmp("Август", "авгусТ") == 0); // Греческий также работает до тех пор, пока не встретится отображение 1:M | Greek also works as long as there is no 1:M mapping in sight assert(sicmp("ΌΎ", "όύ") == 0); // В таких случаях, как следующий, результат сопоставления не даёт равенства // Маленькая греческая буква йота с dialytika и tonos assert(sicmp("ΐ", "\u03B9\u0308\u0301") != 0); // с функцией icmp с этим проблем нет assert(icmp("ΐ", "\u03B9\u0308\u0301") == 0); assert(icmp("ΌΎ", "όύ") == 0);
icmp
(S1, S2)(S1 r1
, S2 r2
)r1
и r2
. Соблюдает правила полной обработки всех случаев отображения. Они включают в себя соответствие в качестве равных немецкой ß с "ss" и другие отображения кодовых точек 1:M в отличие от sicmp. Ценой педантичной правильности этого варианта является слегка худшая производительность.
S1 r1 |
лидирующий диапазон символов |
S2 r2 |
лидирующий диапазон символов |
str1
лексикографически «меньше», чем str2
,> 0, если str1
лексикографически «больше», чем str2
assert(icmp("Rußland", "Russland") == 0); assert(icmp("ᾩ -> \u1F70\u03B9", "\u1F61\u03B9 -> ᾲ") == 0);
icmp
квалификаторами @safe @nogc nothrow pure.
import std.utf : byDchar; assert(icmp("Rußland".byDchar, "Russland".byDchar) == 0); assert(icmp("ᾩ -> \u1F70\u03B9".byDchar, "\u1F61\u03B9 -> ᾲ".byDchar) == 0);
combiningClass
(dchar ch
);
Возвращает класс комбинирования ch
.
// укорачиваем код alias CC = combiningClass; // комбинируемая тильда assert(CC('\u0303') == 230); // комбинируемое кольцо под символом assert(CC('\u0325') == 220); // простое следствие состоит в том, что в последовательности // «тильду» следует помещать после «кольца внизу»
Canonical
Compatibility
Замечание: Разложение совместимости – это преобразование с потерями, обычно подходящее только для поиска нечёткого соответствия и внутренней обработки.
compose
(dchar first
, dchar second
);
first
предшествует второму second
, обычно это означает, что первый является начальным.
Замечание: Эта функция не охватывает хангыльские слоги. См. ниже функцию composeJamo.
assert(compose('A','\u0308') == '\u00C4'); assert(compose('A', 'B') == dchar.init); assert(compose('C', '\u0301') == '\u0106'); // Обратите внимание, что начальным символом является first, // поэтому следующее не компонуется assert(compose('\u0308', 'A') == dchar.init);
decompose
(UnicodeDecomposition decompType = Canonical)(dchar ch
);
ch
. Если разложение недоступно, возвращается графема с самим ch
.
Замечание: Эта функция также разлагает хангыльские слоги, как это предписано стандартом.
import std.algorithm.comparison : equal; assert(compose('A','\u0308') == '\u00C4'); assert(compose('A', 'B') == dchar.init); assert(compose('C', '\u0301') == '\u0106'); // Обратите внимание, что начальным символом является first, // поэтому следующее не компонуется assert(compose('\u0308', 'A') == dchar.init); assert(decompose('Ĉ')[].equal("C\u0302")); assert(decompose('D')[].equal("D")); assert(decompose('\uD4DC')[].equal("\u1111\u1171\u11B7")); assert(decompose!Compatibility('¹')[].equal("1"));
decomposeHangul
(dchar ch
);
ch
не является скомпонованным слогом, тогда эта функция возвращает графему, содержащую только ch
как есть.
import std.algorithm.comparison : equal; assert(decomposeHangul('\uD4DB')[].equal("\u1111\u1171\u11B6"));
composeJamo
(dchar lead
, dchar vowel
, dchar trailing
= (dchar).init);
lead
), гласного vowel
и необязательного согласного jamos trailing
.
lead
и vowel
не является допустимым hangul jamo соответствующего класса символов, возвращается dchar.init.
assert(composeJamo('\u1111', '\u1171', '\u11B6') == '\uD4DB'); // leaving out T-vowel, or passing any codepoint // that is not trailing consonant composes an LV-syllable assert(composeJamo('\u1111', '\u1171') == '\uD4CC'); assert(composeJamo('\u1111', '\u1171', ' ') == '\uD4CC'); assert(composeJamo('\u1111', 'A') == dchar.init); assert(composeJamo('A', '\u1171') == dchar.init);
NormalizationForm
: int;
NFC
NFD
NFKC
NFKD
normalize
(NormalizationForm norm = NFC, C)(inout(C)[] input
);
Замечание: В тех случаях, когда входная строка уже нормализована, она возвращается немодифицированной и распределение памяти не выполняется.
// работает с любыми кодировками wstring greet = "Hello world"; assert(normalize(greet) is greet); // тот же самый срез // Пример символа со всеми четырьмя различными формами: // Греческий символ ипсилон с acute и hook (кодовая точка 0x03D3) assert(normalize!NFC("ϓ") == "\u03D3"); assert(normalize!NFD("ϓ") == "\u03D2\u0301"); assert(normalize!NFKC("ϓ") == "\u038E"); assert(normalize!NFKD("ϓ") == "\u03A5\u0301");
allowedIn
(NormalizationForm norm)(dchar ch
);
ch
(Quick_Check = YES) в форме нормализации norm.
// например, Кириллица всегда разрешена, так же как и ASCII assert(allowedIn!NFC('я')); assert(allowedIn!NFD('я')); assert(allowedIn!NFKC('я')); assert(allowedIn!NFKD('я')); assert(allowedIn!NFC('Z'));
isWhite
(dchar c
);
c
пробельным символом Юникода
(Общая категория: Part of C0(tab, vertical tab, form feed,
carriage return, and linefeed characters), Zs, Zl, Zp, and NEL(U+0085))isLower
(dchar c
);
c
символом Unicode нижнего регистра.
isUpper
(dchar c
);
c
символом Unicode верхнего регистра.
asLowerCase
(Range)(Range str
)asUpperCase
(Range)(Range str
)Range str |
строка или диапазон символов |
import std.algorithm.comparison : equal; assert("hEllo".asUpperCase.equal("HELLO"));
asCapitalized
(Range)(Range str
)Range str |
строка или диапазон символов |
import std.algorithm.comparison : equal; assert("hEllo".asCapitalized.equal("Hello"));
toLowerInPlace
(C)(ref C[] s
)s
в нижний регистр (путем выполнения преобразования в lowercase Unicode). Для некоторых символов длина строки может увеличиться после преобразования, в таком случае функция перераспределяет память ровно один раз. Если массив s
не имеет символов в верхнем регистре, то он не изменяется.
toUpperInPlace
(C)(ref C[] s
)s
в верхний регистр (путем выполнения преобразования в uppercase Unicode). Для некоторых символов длина строки может увеличиться после преобразования, в таком случае функция перераспределяет память ровно один раз. Если массив s
не имеет символов в нижнем регистре, то он не изменяется.
c
является символом верхнего регистра Юникода, возвращается его эквивалент в нижнем регистре. В противном случае возвращается c
.
Предупреждение:
некоторые алфавиты, такие, как немецкий и греческий, не имеют возможности выполнять преобразование верхний-нижний регистр 1:1. Используйте перегрузку toLower
, которая в отличие от этого варианта принимает полную строку.
toLower
(S)(S s
)s
, за исключением того, что все её символы преобразуются в нижний регистр (путем выполнения преобразования в lowercase Unicode). Если ни один из символов s
не изменяется, возвращается сама s
.
c
является символом нижнего регистра Юникода, возвращается его эквивалент в верхнем регистре. В противном случае возвращается c
.
Предупреждение:
некоторые алфавиты, такие, как немецкий и греческий, не имеют возможности выполнять преобразование верхний-нижний регистр 1:1. Используйте перегрузку toUpper
, которая в отличие от этого варианта принимает полную строку.
toUpper
можно использовать в качестве аргумента для функции std.algorithm.iteration.map для создания алгоритма, который сможет преобразовывать диапазон символов в верхний регистр без выделения памяти. Строку после этого можно создать, используя std.algorithm.mutation.copy, чтобы отправить её в std.array.appender.
import std.algorithm.iteration : map; import std.algorithm.mutation : copy; import std.array : appender; auto abuf = appender!(char[])(); "hello".map!toUpper.copy(&abuf); assert(abuf.data == "HELLO");
toUpper
(S)(S s
)s
, за исключением того, что все её символы преобразуются в верхний регистр (путем выполнения преобразования в uppercase Unicode). Если ни один из символов s
не был затронут, возвращается сама s
.
isAlpha
(dchar c
);
c
буквой Юникода (общее свойство Юникода: Alphabetic).
isMark
(dchar c
);
c
знаком Unicode (общая категория Unicode: Mn, Me, Mc).
isNumber
(dchar c
);
c
числовым символом Unicode (общая категория Unicode: Nd, Nl, No).
isAlphaNum
(dchar c
);
c
буквенным или числовым символом Unicode. (Общая категория Unicode: Alphabetic, Nd, Nl, No).
dchar c |
любой символ Юникода |
isPunctuation
(dchar c
);
c
символом пунктуации Unicode (общая категория Unicode: Pd, Ps, Pe, Pc, Po, Pi, Pf).
isSymbol
(dchar c
);
c
символом Unicode symbol
(общая категория Unicode: Sm, Sc, Sk, So).isSpace
(dchar c
);
c
символом пробела Unicode (общая категория Unicode: Zs)
isGraphical
(dchar c
);
c
графическим символом Unicode (общая категория Unicode: L, M, N, P, S, Zs).
isControl
(dchar c
);
c
управляющим символом Unicode (общая категория Unicode: Cc).
isFormat
(dchar c
);
c
форматирующим символом Unicode (общая категория Unicode: Cf).
isPrivateUse
(dchar c
);
c
кодовой точкой Unicode для частного использования (общая категория Unicode: Co).
isSurrogate
(dchar c
);
c
суррогатной кодовой точкой Unicode (общая категория Unicode: Cs).
isSurrogateHi
(dchar c
);
c
is a Unicode high surrogate (lead surrogate).isSurrogateLo
(dchar c
);
c
is a Unicode low surrogate (trail surrogate).isNonCharacter
(dchar c
);
c
не-символом Unicode, то есть кодовой точкой без назначенного абстрактного символа. (Общая категория Unicode: Cn)