std.uni

Переместиться к: 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.

Абстрактный символ (Abstract character)
Единица информации, используемая для организации, контроля или представления текстовых данных. Обратите внимание, что:

Каноническое разложение (Canonical decomposition)
Разложение символа или символьной последовательности, которое возникает из-за рекурсивного применения канонических отображений, основанных на базе данных символов Юникода (Unicode Character Database), и описанных в «Conjoining Jamo Behavior» (раздел 12 Unicode Conformance).

Каноническая компоновка (Canonical composition)
Точное определение канонической компоновки – это алгоритм, указанный в 11 разделе Unicode Conformance. Неофициально это процесс, обратный каноническому разложению с добавлением определённых правил, например, предотвращение появления устаревших символов в скомпонованном результате.

Канонический эквивалент (Canonical equivalent)
Две последовательности символов называются каноническими эквивалентами, если их полные канонические разложения идентичны.

Символ (Character)
Как правило, отличается в зависимости от контекста. Для целей этой документации термин символ означает кодированный символ, то есть кодовую точку, имеющую назначенный абстрактный символ (символьное значение).

Кодовая точка (Code point)
В отдельных переводах документации по Unicode применяется термин Кодовая позиция – прим. пер.
Любое значение в кодовом пространстве Unicode; то есть в диапазоне целых чисел от 0 до 10FFFF (hex). Не все кодовые точки назначены кодированным символам.

Кодовый блок (Code unit)
Минимальная комбинация битов, которая может представить собой единицу кодированного текста для обработки или обмена. В зависимости от кодировки это могут быть: 8-битные кодовые блоки в UTF-8 (char), 16-битные кодовые блоки в UTF-16 (wchar) и 32-битные кодовые блоки в UTF-32 (dchar). Обратите внимание, что в UTF-32 кодовый блок является кодовой точкой и представлен D-типом dchar.

Комбинируемый символ (Combining character)
Символ с Общей категорией Combining Mark (M).

Класс комбинирования (Combining class)
Численное значение, используемое каноническим алгоритмом упорядочения Unicode для определения того, какие последовательности комбинируемых знаков (combining marks) следует считать канонически эквивалентными, а какие нет.

Разложение совместимости (Compatibility decomposition)
Разложение символа или последовательности символов, которое возникает из-за рекурсивного применения как отображений совместимости, так и канонических отображений, основанных на базе данных символов Юникода (Unicode Character Database), и описанных в «Conjoining Jamo Behavior», после чего никакие символы не могут быть разложены далее.

Совместимый эквивалент (Compatibility equivalent)
Две последовательности символов называются совместимыми эквивалентами, если их полные разложения совместимости идентичны.

Кодированный символ (Encoded character)
Связь (или отображение) между абстрактным символом и кодовой точкой.

Глиф (Glyph)
Фактическое, конкретное изображение представления глифа, которое было растеризовано или иным образом изображено на поверхности какого-либо дисплея.
Какое-то бессмысленно-рекурсивное определение... Надеюсь, я правильно понял, что это просто изображение буквы или знака – прим.пер.

Основная графема (Grapheme base)
Символ со свойством Grapheme_Base или любой стандартный корейский слоговый блок.

Кластер графем (Grapheme cluster)
Определяется как текст между границами графем, как это описано в Стандарте Unicode, приложение №29, Unicode text segmentation. Важные общие свойства графемы:

Этот модуль определяет ряд примитивов, которые работают с графемами: Grapheme, decodeGrapheme и graphemeStride. Все они используют границы расширенных графем (extended grapheme), как это описано в вышеупомянутом приложении к стандарту.

Непромежуточный знак (Nonspacing mark)
Комбинируемый символ с Общей категорией Nonspacing Mark (Mn) или Enclosing Mark (Me).

Промежуточный знак (Spacing mark)
Комбинируемый символ, который не является непромежуточным знаком.

Тоже какие-то бюрократически бессмысленные определения, как с глифом... Как я понял по картинкам, 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

Это полный список свойств Юникода, доступных через структуру unicode. Обратитесь к утилите CLDR, если у вас есть сомнения относительно содержимого определенного набора.

Наборы общей категории, перечисленные ниже, доступны только с помощью сокращённого доступа через структуру unicode.

Общая категория (General category)
Сокр. Длинная форма Сокр. Длинная формаСокр. Длинная форма
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:

Общие бинарные свойства (Common binary properties)
Наименование Наименование Наименование
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" к именам блоков, для различения сценариев и блоков.

Блоки (Blocks)
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:

Сценарии (Scripts)
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.

Типы слогов хангыля (Hangul syllable type)
Сокр. Длинная форма
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.

Лицензия:
Boost License 1.0.
Авторы:
Dmitry Olshansky

Исходный код: std/uni.d

Стандарты:
Unicode v6.2
enum dchar lineSep;
Константа кодовой точки (0x2028) – разделитель строк.
enum dchar paraSep;
Константа кодовой точки (0x2029) – разделитель абзацев.
enum dchar nelSep;
Константа кодовой точки (0x0085) – следующая строка.
template isCodepointSet(T)
Проверяет, является ли T некоторым набором кодовых точек. Предназначен для ограничений шаблона.
enum auto isIntegralPair(T, V = uint);
Проверяет, является ли T парой целых чисел, которые неявно преобразуются в V. Следующий код должен компилироваться для любой пары T:
(T x){ V a = x[0]; V b = x[1];}
Следующее не должно компилироваться:
(T x){ V c = x[2];}
alias CodepointSet = InversionList!(GcPolicy).InversionList;
Рекомендуемый тип по умолчанию для набора кодовых точек. Для получения дополнительной информации смотрите текущую реализацию: InversionList.
struct CodepointInterval;
Рекомендуемый тип std.typecons.Tuple представляет интервалы кодовых точек [a, b). Как используется в InversionList. Любой тип интервала должен проходить проверку isIntegralPair.

Переместиться к: add · byCodepoint · byInterval · empty · inverted · length · opBinary · opBinaryRight · opIndex · opOpAssign · opUnary · this · toSourceCode · toString

struct 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 на протяжении всей кодовой базы.

Переместиться к: 2 · 3

pure this(Set)(Set set)
if (isCodepointSet!Set);
Построить из другого набора кодовых точек set любого типа.
pure this(Range)(Range intervals)
if (isForwardRange!Range && isIntegralPair!(ElementType!Range));
Построить набор из лидирующего диапазона интервалов кодовых точек intervals.
this()(uint[] 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));
@property auto byInterval();
Получить диапазон, который охватывает все интервалы кодовых точек в этом InversionList.

Пример:

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')]));

const bool opIndex(uint val);
Проверяет наличие кодовой точки val в этом наборе.
Примеры:
auto gothic = unicode.Gothic;
// готическая буква ahsa
assert(gothic['\U00010330']);
// очевидно, ascii-символы в Gothic отсутствуют
assert(!gothic['$']);
@property size_t length();
Количество кодовых точек в этом наборе
This opBinary(string op, U)(U rhs)
if (isCodepointSet!U || is(U : dchar));

Устанавливает поддержку естественного синтаксиса для алгебры множеств, а именно:

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);
ref This opOpAssign(string op, U)(U rhs)
if (isCodepointSet!U || is(U : dchar));
'op=' версии вышеперечисленных перегруженных операторов.
const bool opBinaryRight(string op : "in", U)(U ch)
if (is(U : dchar));
Проверяет наличие кодовой точки ch в этом наборе, то же, что и opIndex.
Примеры:
assert('я' in unicode.Cyrillic);
assert(!('z' in unicode.Cyrillic));
auto opUnary(string op : "!")();
Получить набор, являющийся инверсией этого набора.
Смотрите также:
@property auto byCodepoint();
Диапазон, который проходит по каждой из кодовых точек в этом наборе.
Примеры:
import std.algorithm.comparison : equal;
import std.range : iota;

auto set = unicode.ASCII;
set.byCodepoint.equal(iota(0, 0x80));
void toString(Writer)(scope Writer sink, FormatSpec!char fmt);
Получить текстовое представление этого InversionList в виде открытых справа интервалов.
Флаг форматирования применяется индивидуально для каждого значения, например:
  • %s и %d форматируют интервал как диапазон [нижний..верхний) целых
  • %x форматирует интервал как диапазон [нижний..верхний) шестнадцатеричных символов в нижнем регистре
  • %X форматирует интервал как диапазон [нижний..верхний) шестнадцатеричных символов в верхнем регистре
  • Примеры:
    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)");
    
    ref auto 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']);
    
    @property auto inverted();
    Получить набор, являющийся инверсией этого множества.
    Смотрите '!' opUnary для того же самого, но с использованием операторов.
    Примеры:
    auto set = unicode.ASCII;
    // Объединение с инверсией даст все кодовые точки в Unicode
    assert((set | set.inverted).length == 0x110000);
    // нет пересечений с инверсией
    assert((set & set.inverted).empty);
    
    string toSourceCode(string funcName = "");
    Генерирует строку с D-кодом унарной функции с именем funcName, принимающей один аргумент типа dchar. Если funcName пусто, код формируется в виде лямбда-функции.
    Сгенерированная функция тестирует, принадлежит ли этому набору переданная кодовая точка или нет. Результат должен использоваться со строковым mixin. Предполагаемая область использования – это агрессивная оптимизация посредством метапрограмм в генераторах парсеров и т.п.

    Замечание: Используйте с осторожностью для относительно небольших или стандартных наборов. Это может быть медленнее, чем просто использование многоэтапных таблиц.

    Пример:

    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;
        }
    }
    

    const @property bool empty();
    Возвращает Истину, если этот набор не содержит кодовых точек.
    Примеры:
    CodepointSet emptySet;
    assert(emptySet.length == 0);
    assert(emptySet.empty);
    
    template codepointSetTrie(sizes...) if (sumOfIntegerTuple!sizes == 21)
    Короткая форма для создания собственной многоуровневой фиксированной таблицы Trie из набора CodepointSet. Размеры sizes – это количество бит на каждый из уровней, причем более важные биты используются в первую очередь.

    Замечание: Сумма sizes должна быть равна 21.

    Смотрите также:
    toTrie, которая ещё проще.

    Пример:

    {
        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 числовых кодовых точек
        }
    }
    

    template CodepointSetTrie(sizes...) if (sumOfIntegerTuple!sizes == 21)
    Тип таблицы Trie, генерируемый функцией codepointSetTrie.
    template codepointTrie(T, sizes...) if (sumOfIntegerTuple!sizes == 21)
    Несколько более общий инструмент для создания фиксированной таблицы Trie для Unicode-данных.
    В отличие от codepointSetTrie, он позволяет создавать отображения dchar на произвольный тип T.

    Замечание: Перегрузка с помощью наборов CodepointSet, естественно, будет конвертировать только в таблицы Trie, отображающие в bool.

    template CodepointTrie(T, sizes...) if (sumOfIntegerTuple!sizes == 21)
    Тип таблицы Trie, генерируемый функцией codepointTrie.

    Переместиться к: match · skip · subMatcher · test

    struct MatcherConcept;
    Наиболее подходящим в данном случае переводом слова Matcher будет Обнаружитель совпадений. К сожалению, моей фантазии не хватило, чтобы адекватно вставить это словосочетание в предложения, так что оставлю это слово без перевода – прим. пер.
    Концептуальный тип, который описывает общие свойства всех UTF Matchers.

    Замечание: Только для иллюстрации, вызов любого из этих методов приведёт к ошибке утверждения (assertion failure). Используйте utfMatcher для получения конкретного matcher для кодировок UTF-8 или UTF-16.

    bool match(Range)(ref Range inp)
    if (isRandomAccessRange!Range && is(ElementType!Range : char));

    bool skip(Range)(ref Range inp)
    if (isRandomAccessRange!Range && is(ElementType!Range : char));

    bool test(Range)(ref Range inp)
    if (isRandomAccessRange!Range && is(ElementType!Range : char));

    Выполняет семантический эквивалент двух операций: декодирование кодовой точки спереди 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 никогда не влияет на аргумент
    
    @property auto subMatcher(Lengths...)();
    Расширенная возможность – предоставляет прямой доступ к подмножеству matcher на основе набора известных длин кодирования. Длины представлены в кодовых блоках. Затем sub-matcher может выполнять меньше операций при выполнении любого test/match.
    Используйте с осторожностью, поскольку sub-matcher не будет соответствовать кодовым точкам, которые имеют кодированную длину, не принадлежащую выбранному набору длин. Кроме того, объект sub-matcher ссылается на родительский matcher и не должен использоваться по истечении его времени жизни.
    Еще одно предостережение в использовании sub-matcher заключается в том, что skip недоступен именно потому, что sub-matcher не обнаруживает всех длин.
    Примеры:
    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)); // И '²' тоже
    
    enum auto isUtfMatcher(M, C);
    Проверяет, является ли M UTF-Matcher'ом для диапазонов символов типа C .
    @trusted auto utfMatcher(Char, Set)(Set set)
    if (isCodepointSet!Set);
    Создаёт объект matcher для классификации кодовых точек из набора для кодирования set, который использует Char в качестве кодового блока.
    Смотрите схему API в описании MatcherConcept.
    auto toTrie(size_t level, Set)(Set set)
    if (isCodepointSet!Set);
    Удобная функция для построения оптимальных конфигураций упакованных таблиц Trie из любого набора кодовых точек set.
    Параметр level указывает количество используемых уровней trie, допустимые значения: 1, 2, 3 или 4. Они представляют разные уровни компромисса между скоростью и используемым размером таблицы.

    Уровень 1 самый быстрый и самый прожорливый по памяти (битовый массив).

    Уровень 4 является самым медленным и занимает меньше всего места.

    Смотрите раздел Краткий обзор для примера.

    Замечание: Уровень 4 остаётся очень практичным (быстрее и более предсказуем) по сравнению с использованием прямого поиска на самом наборе set.

    auto toDelegate(Set)(Set set)
    if (isCodepointSet!Set);

    Создаёт таблицу Trie с в основном оптимальным компромиссом скорость-размер, и заворачивает её в делегат следующего типа: bool delegate(dchar ch).

    Эффективно для создания «лямбда-тестеров», подходящих для алгоритмов вроде std.algorithm.find, принимающих унарные предикаты.

    Смотрите раздел Краткий обзор для примера.

    Переместиться к: block · hangulSyllableType · opCall · opDispatch · script

    struct unicode;
    Единая точка входа для поиска наборов кодовых точек Юникода по имени или псевдониму блока, сценария или общей категории.
    Используются четко определенные стандартные правила поиска свойства по имени. Они включают в себя нечеткое сопоставление имен, так что «White_Space», «white-SpAce» и «whitespace» считаются равными и дают одинаковый набор пробельных символов.
    pure @property auto opDispatch(string name)();
    Выполняет поиск набора кодовых точек с проверкой правильности времени компиляции. Эта короткая версия сочетает в себе 3 поиска: по блокам, сценариям и общим двоичным свойствам.
    Обратите внимание, что, поскольку сценарии и блоки перекрываются, используется обычный трюк для устранения неоднозначности – для получения блока используйте unicode.InBlockName, для поиска сценария используйте unicode.ScriptName.
    Смотрите также:
    block, script и (не включенный в этот поиск) hangulSyllableType.
    auto opCall(C)(in C[] name)
    if (is(C : dchar));
    Тот же поиск по блокам, сценариям или двоичным свойствам, но предназначенный для времени выполнения. Эта версия предоставляется для случаев, когда имя name не известно заранее; в противном случае, вариант времени компиляции opDispatch, как правило, лучший выбор.
    Смотрите в таблице свойств доступные наборы.
    struct 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);
    
    struct 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);
    
    struct hangulSyllableType;
    Получение набора кодовых точек, которые имеют заданный тип слога в хангыле.
    Другие не двоичные свойства (в случае их поддержки) следуют той же нотации - unicode.propertyName.propertyValue для доступа, проверяемого во время компиляции, и unicode.propertyName(propertyValue) для доступа, проверяемого вол время выполнения.
    См. в таблице свойств существующие наборы.
    Примеры:
    // L здесь - это тип слога, а не буква в Юникоде. L - это сокращение
    auto leadingVowel = unicode.hangulSyllableType("L");
    // Убеждаемся, что присутствуют некоторые ведущие гласные
    foreach (vowel; '\u1110'..'\u115F')
        assert(leadingVowel[vowel]);
    assert(leadingVowel == unicode.hangulSyllableType.L);
    
    size_t graphemeStride(C)(in C[] input, size_t index)
    if (is(C : dchar));
    Вычисляет длину графемного кластера, начинающегося с индекса 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");
    
    Grapheme decodeGrapheme(Input)(ref Input inp)
    if (isInputRange!Input && is(Unqual!(ElementType!Input) == dchar));
    Считывает один полный графемный кластер из входного диапазона inp с типом dchar.
    Примеры смотрите в разделе Grapheme ниже.

    Замечание: Эта функция изменяет inp и, следовательно, inp должен быть L-значением.

    auto byGrapheme(Range)(Range range)
    if (isInputRange!Range && is(Unqual!(ElementType!Range) == dchar));

    Итерирует строку по графемам.

    Полезно для выполнения манипуляций над строками, в которых требуется информация о графемах.

    Смотрите также:
    Примеры:
    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));
    
    auto byCodePoint(Range)(Range range)
    if (isInputRange!Range && is(Unqual!(ElementType!Range) == Grapheme));

    Range byCodePoint(Range)(Range range)
    if (isInputRange!Range && is(Unqual!(ElementType!Range) == dchar));

    Лениво преобразует диапазон графем в диапазон кодовых точек.

    Полезно для преобразования результата в строку после выполнения операций над графемами.

    Действует как тождественная функция при получении диапазона кодовых точек.

    Примеры:
    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

    struct Grapheme;

    Структура, предназначенная для эффективной упаковки символов графемного кластера.

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

    Смотрите также:
    this(C)(in C[] chars...)
    if (is(C : dchar));

    this(Input)(Input seq)
    if (!isDynamicArray!Input && isInputRange!Input && is(ElementType!Input : dchar));
    Ctor
    const pure nothrow @nogc @trusted dchar opIndex(size_t index);
    Получение кодовой точки по данному индексу index в этом кластере.
    pure nothrow @nogc @trusted void 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);
    
    pure nothrow @nogc @system SliceOverIndexed!Grapheme opSlice(size_t a, size_t b);

    pure nothrow @nogc @system SliceOverIndexed!Grapheme opSlice();
    Диапазон с произвольным доступом символов графемы.

    Предупреждение: Становится недействительным, когда эта графема покидает область видимости, после этого попытки использовать этот диапазон приведут к повреждению памяти.

    const pure nothrow @nogc @property @trusted size_t length();
    Длина графемного кластера в кодовых точках.

    Переместиться к: 2

    ref auto opOpAssign(string op)(dchar ch);
    Добавляет символ 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"));
    
    ref auto opOpAssign(string op, Input)(Input inp)
    if (isInputRange!Input && is(ElementType!Input : dchar));
    Добавляет все символы из входного диапазона inp в эту графему.
    @property bool valid()();
    Истина, если этот объект содержит действительный расширенный кластер графем. Примитивы декодирования этого модуля всегда возвращают действительную графему.
    Добавление и непосредственная манипуляция символами графемы может сделать её более недействительной. Некоторые приложения могут использовать Grapheme как «небольшую строку» любых кодовых точек и полностью игнорировать это свойство.
    int sicmp(S1, S2)(S1 str1, S2 str2)
    if (isSomeString!S1 && isSomeString!S2);

    Выполняет тривиальное нечувствительное к регистру сравнение строк str1 и str2. Эта функция использует более простое правило сравнения, таким образом обеспечивая лучшую производительность, чем icmp. Однако имейте в виду предупреждение ниже.

    Параметры:
    S1 str1 строка
    S2 str2 строка
    Возвращает:
    Целое типа int, равное 0, если строки равны, <0, если 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);
    
    int icmp(S1, S2)(S1 r1, S2 r2)
    if (isForwardRange!S1 && isSomeChar!(ElementEncodingType!S1) && isForwardRange!S2 && isSomeChar!(ElementEncodingType!S2));
    Выполняет сравнение без учета регистра r1 и r2. Соблюдает правила полной обработки всех случаев отображения. Они включают в себя соответствие в качестве равных немецкой ß с "ss" и другие отображения кодовых точек 1:M в отличие от sicmp. Ценой педантичной правильности этого варианта является слегка худшая производительность.
    Параметры:
    S1 r1 лидирующий диапазон символов
    S2 r2 лидирующий диапазон символов
    Возвращает:
    Целое типа int, равное 0, если строки соответствуют друг другу, <0, если str1 лексикографически «меньше», чем str2,> 0, если str1 лексикографически «больше», чем str2
    Смотрите также:
    Примеры:
    assert(icmp("Rußland", "Russland") == 0);
    assert(icmp("ᾩ -> \u1F70\u03B9", "\u1F61\u03B9 -> ᾲ") == 0);
    
    Примеры:
    Используя шаблон std.utf.byUTF и его псевдонимы, можно избежать возбуждения исключений и выделения памяти сборщиком мусора посредством автоматического декодирования, что наделяет функцию 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);
    
    pure nothrow @nogc @safe ubyte combiningClass(dchar ch);

    Возвращает класс комбинирования ch.

    Примеры:
    // укорачиваем код
    alias CC = combiningClass;
    
    // комбинируемая тильда
    assert(CC('\u0303') == 230);
    // комбинируемое кольцо под символом 
    assert(CC('\u0325') == 220);
    // простое следствие состоит в том, что в последовательности 
    // «тильду» следует помещать после «кольца внизу» 
    

    Переместиться к: Canonical · Compatibility

    enum UnicodeDecomposition: int;
    Тип разложения символов Unicode.
    Canonical
    Каноническое разложение. В результате получается канонический эквивалент последовательности.
    Compatibility
    Разложение совместимости. В результате получается совместимый эквивалент последовательности.

    Замечание: Разложение совместимости – это преобразование с потерями, обычно подходящее только для поиска нечёткого соответствия и внутренней обработки.

    pure nothrow @safe dchar compose(dchar first, dchar second);
    Пытается канонически скомпоновать 2 символа. Возвращает скомпонованный символ, это получилось, или dchar.init в противном случае.
    Предполагается, что в оригинальном тексте первый символ 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);
    
    @safe Grapheme decompose(UnicodeDecomposition decompType = Canonical)(dchar ch);
    Возвращает полное каноническое разложение (по умолчанию), или разложение совместимости символа ch. Если разложение недоступно, возвращается графема с самим ch.

    Замечание: Эта функция также разлагает хангыльские слоги, как это предписано стандартом.

    Смотрите также:
    decomposeHangul для ограниченной версии, которая работает только с хангыльскими слогами, но не выполняет других разложений.
    Примеры:
    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"));
    
    @safe Grapheme decomposeHangul(dchar ch);
    Выполняет разложение хангыльского слога. Если ch не является скомпонованным слогом, тогда эта функция возвращает графему, содержащую только ch как есть.
    Примеры:
    import std.algorithm.comparison : equal;
    assert(decomposeHangul('\uD4DB')[].equal("\u1111\u1171\u11B6"));
    
    pure nothrow @nogc @safe dchar composeJamo(dchar lead, dchar vowel, dchar trailing = (dchar).init);
    Пытается скомпоновать хангыльский слог из ведущего согласного (lead), гласного vowel и необязательного согласного jamos trailing.
    При успехе возвращается скомпонованный хангыльский слог LV или LVT.
    Если что-либо из 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);
    
    enum NormalizationForm: int;
    Тип перечисления для форм нормализации, передаваемый в качестве параметра шаблона для таких функций, как normalize.
    NFC

    NFD

    NFKC

    NFKD
    Сокращения-псевдоним от значений, указывающих формы нормализации.
    inout(C)[] normalize(NormalizationForm norm = NFC, C)(inout(C)[] input);
    Возвращает входную строку, нормированную в выбранную форму. Форма C используется по умолчанию.
    Для получения дополнительной информации о формах нормализации смотрите Раздел о нормализации.

    Замечание: В тех случаях, когда входная строка уже нормализована, она возвращается немодифицированной и распределение памяти не выполняется.

    Примеры:
    // работает с любыми кодировками
    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");
    
    bool allowedIn(NormalizationForm norm)(dchar ch);
    Проверяет, всегда ли допустим символ dchar ch (Quick_Check = YES) в форме нормализации norm.
    Примеры:
    // например, Кириллица всегда разрешена, так же как и ASCII 
    assert(allowedIn!NFC('я'));
    assert(allowedIn!NFD('я'));
    assert(allowedIn!NFKC('я'));
    assert(allowedIn!NFKD('я'));
    assert(allowedIn!NFC('Z'));
    
    pure nothrow @nogc @safe bool isWhite(dchar c);
    Проверяет, является ли или нет c пробельным символом Юникода (Общая категория: Part of C0(tab, vertical tab, form feed, carriage return, and linefeed characters), Zs, Zl, Zp, and NEL(U+0085))
    pure nothrow @nogc @safe bool isLower(dchar c);
    Возвращает, является ли c символом Unicode нижнего регистра.
    pure nothrow @nogc @safe bool isUpper(dchar c);
    Возвращает, является ли c символом Unicode верхнего регистра.
    auto asLowerCase(Range)(Range str)
    if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range);

    auto asUpperCase(Range)(Range str)
    if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range);
    Преобразует входной диапазон или строку в верхний или нижний регистр.
    Не выделяет память. Символы в формате UTF-8 или UTF-16, которые не могут быть декодированы, обрабатываются как std.utf.replacementDchar.
    Параметры:
    Range str строка или диапазон символов
    Возвращает:
    входной диапазон символов типа dchar
    Смотрите также:
    Примеры:
    import std.algorithm.comparison : equal;
    
    assert("hEllo".asUpperCase.equal("HELLO"));
    
    auto asCapitalized(Range)(Range str)
    if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range);
    Преобразует диапазон ввода или строку к виду, в котором первый символ в верхнем регистрt, а последующие символы в нижнем регистре. (В терминологии текстового процессора Microsoft Word "Как в предложениях" - прим. пер.)
    Does not allocate memory. Не выделяет память. Символы в формате UTF-8 или UTF-16, которые не могут быть декодированы, обрабатываются как std.utf.replacementDchar.
    Параметры:
    Range str строка или диапазон символов
    Возвращает:
    входной диапазон символов типа dchar
    Смотрите также:
    Примеры:
    import std.algorithm.comparison : equal;
    
    assert("hEllo".asCapitalized.equal("Hello"));
    
    pure @trusted void toLowerInPlace(C)(ref C[] s)
    if (is(C == char) || is(C == wchar) || is(C == dchar));
    Преобразует s в нижний регистр (путем выполнения преобразования в lowercase Unicode). Для некоторых символов длина строки может увеличиться после преобразования, в таком случае функция перераспределяет память ровно один раз. Если массив s не имеет символов в верхнем регистре, то он не изменяется.
    pure @trusted void toUpperInPlace(C)(ref C[] s)
    if (is(C == char) || is(C == wchar) || is(C == dchar));
    Преобразует s в верхний регистр (путем выполнения преобразования в uppercase Unicode). Для некоторых символов длина строки может увеличиться после преобразования, в таком случае функция перераспределяет память ровно один раз. Если массив s не имеет символов в нижнем регистре, то он не изменяется.

    Переместиться к: 2

    pure nothrow @nogc @safe dchar toLower(dchar c);
    Если c является символом верхнего регистра Юникода, возвращается его эквивалент в нижнем регистре. В противном случае возвращается c.

    Предупреждение: некоторые алфавиты, такие, как немецкий и греческий, не имеют возможности выполнять преобразование верхний-нижний регистр 1:1. Используйте перегрузку toLower, которая в отличие от этого варианта принимает полную строку.

    pure @trusted S toLower(S)(S s)
    if (isSomeString!S);
    Возвращает строку, которая идентична s, за исключением того, что все её символы преобразуются в нижний регистр (путем выполнения преобразования в lowercase Unicode). Если ни один из символов s не изменяется, возвращается сама s.

    Переместиться к: 2

    pure nothrow @nogc @safe dchar toUpper(dchar c);
    Если 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");
    
    pure @trusted S toUpper(S)(S s)
    if (isSomeString!S);
    Возвращает строку, которая идентична s, за исключением того, что все её символы преобразуются в верхний регистр (путем выполнения преобразования в uppercase Unicode). Если ни один из символов s не был затронут, возвращается сама s.
    pure nothrow @nogc @safe bool isAlpha(dchar c);
    Возвращает, является ли c буквой Юникода (общее свойство Юникода: Alphabetic).
    pure nothrow @nogc @safe bool isMark(dchar c);
    Возвращает, является ли c знаком Unicode (общая категория Unicode: Mn, Me, Mc).
    pure nothrow @nogc @safe bool isNumber(dchar c);
    Возвращает, является ли c числовым символом Unicode (общая категория Unicode: Nd, Nl, No).
    pure nothrow @nogc @safe bool isAlphaNum(dchar c);
    Возвращает, является ли c буквенным или числовым символом Unicode. (Общая категория Unicode: Alphabetic, Nd, Nl, No).
    Параметры:
    dchar c любой символ Юникода
    Возвращает:
    true, если символ входит в категории Unicode Alphabetic, Nd, Nl, или No
    pure nothrow @nogc @safe bool isPunctuation(dchar c);
    Возвращает, является ли c символом пунктуации Unicode (общая категория Unicode: Pd, Ps, Pe, Pc, Po, Pi, Pf).
    pure nothrow @nogc @safe bool isSymbol(dchar c);
    Возвращает, является ли c символом Unicode symbol (общая категория Unicode: Sm, Sc, Sk, So).
    Один из тех случаев, когда два разных английских слова ("character" и "symbol") на русский переводятся одинаково как "символ", обычно бывает наоборот. Т.к. до сих пор в этом описании модуля std.uni авторы везде использовали слово "character", то слово "symbol" я здесь оставляю без перевода, чтобы оно отличалось. Здесь это математические символы, символы валют, модифицирующие символы и символы псевдографики – прим. пер.
    pure nothrow @nogc @safe bool isSpace(dchar c);
    Возвращает, является ли c символом пробела Unicode (общая категория Unicode: Zs)

    Замечание: Сюда не включены символы '\n', '\r', \t' и другие не-пробелы. Для широко используемой менее строгой семантики смотрите isWhite.

    pure nothrow @nogc @safe bool isGraphical(dchar c);
    Возвращает, является ли c графическим символом Unicode (общая категория Unicode: L, M, N, P, S, Zs).
    pure nothrow @nogc @safe bool isControl(dchar c);
    Возвращает, является ли c управляющим символом Unicode (общая категория Unicode: Cc).
    pure nothrow @nogc @safe bool isFormat(dchar c);
    Возвращает, является ли c форматирующим символом Unicode (общая категория Unicode: Cf).
    pure nothrow @nogc @safe bool isPrivateUse(dchar c);
    Возвращает, является ли c кодовой точкой Unicode для частного использования (общая категория Unicode: Co).
    pure nothrow @nogc @safe bool isSurrogate(dchar c);
    Возвращает, является ли c суррогатной кодовой точкой Unicode (общая категория Unicode: Cs).
    pure nothrow @nogc @safe bool isSurrogateHi(dchar c);
    Returns whether c is a Unicode high surrogate (lead surrogate).
    pure nothrow @nogc @safe bool isSurrogateLo(dchar c);
    Returns whether c is a Unicode low surrogate (trail surrogate).
    pure nothrow @nogc @safe bool isNonCharacter(dchar c);
    Возвращает, является ли c не-символом Unicode, то есть кодовой точкой без назначенного абстрактного символа. (Общая категория Unicode: Cn)