Поделиться через


Теперь StringInfo и TextElementEnumerator совместимы с UAX29

До этого изменения System.Globalization.StringInfo и System.Globalization.TextElementEnumerator обрабатывали все кластеры графем неправильно. Некоторые графемы были разбиты на составные компоненты, а не объединялись. Теперь StringInfo и TextElementEnumerator обрабатывают кластеры графем в соответствии с последней версией стандарта Юникода.

Кроме того, метод Microsoft.VisualBasic.Strings.StrReverse, который меняет порядок символов строки в Visual Basic на обратный, теперь также соответствует стандарту Юникода для кластеров графем.

Описание изменения

Графема или расширенный кластер графем — это отдельный воспринимаемый пользователем символ, который может состоять из нескольких кодовых точек Юникода. Например, строка, содержащая тайский символ "кам" (กำ), состоит из двух следующих символов:

  • ก (= '\u0e01') — тайский символ "ко кай"
  • ำ (= '\u0e33') — тайский символ "сара ам"

При отображении пользователю операционная система объединяет эти два символа для формирования одного отображаемого символа (или графемы) "кам" или กำ. Эмодзи также могут состоять из нескольких символов, объединенных для единообразного отображения.

Совет

В документации по .NET при ссылке на графему иногда применяется термин "текстовый элемент".

Классы StringInfo и TextElementEnumerator проверяют строки и возвращают сведения о содержащихся в них графемах. В .NET Framework (все версии) и .NET Core 3.x и более ранних версий эти два класса используют пользовательскую логику, которая обрабатывает некоторые комбинирующие классы, но не полностью соответствует стандарту Юникода. Например, классы StringInfo и TextElementEnumerator ошибочно разделяют один тайский символ "кам" на составляющие компоненты вместо того, чтобы объединить их. Эти классы также ошибочно разбивают символ эмодзи "🤷🏽‍♀️" на четыре кластера (пожимание плечами, модификатор тона кожи, модификатор пола и невидимый объединяющий блок) вместо того, чтобы объединить их в один кластер графем.

Начиная с .NET 5, StringInfo и TextElementEnumerator классы реализуют стандарт Юникода, как определено в приложении Юникод standard #29, ред. 35, с. 3. В частности, теперь они возвращают расширенные кластеры графем для всех комбинирующих классов.

Рассмотрим следующий код C#:

using System.Globalization;

static void Main(string[] args)
{
    PrintGraphemes("กำ");
    PrintGraphemes("🤷🏽‍♀️");
}

static void PrintGraphemes(string str)
{
    Console.WriteLine($"Printing graphemes of \"{str}\"...");
    int i = 0;

    TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(str);
    while (enumerator.MoveNext())
    {
        Console.WriteLine($"Grapheme {++i}: \"{enumerator.Current}\"");
    }

    Console.WriteLine($"({i} grapheme(s) total.)");
    Console.WriteLine();
}

В .NET Framework и .NET Core 3.x и более ранних версий графемы разделяются, а выходные данные в консоли выглядят следующим образом:

Printing graphemes of "กำ"...
Grapheme 1: "ก"
Grapheme 2: "ำ"
(2 grapheme(s) total.)

Printing graphemes of "🤷🏽‍♀️"...
Grapheme 1: "🤷"
Grapheme 2: "🏽"
Grapheme 3: "‍"
Grapheme 4: "♀️"
(4 grapheme(s) total.)

В .NET 5 и более поздних версий графемы объединяются, а выходные данные в консоли выглядят следующим образом:

Printing graphemes of "กำ"...
Grapheme 1: "กำ"
(1 grapheme(s) total.)

Printing graphemes of "🤷🏽‍♀️"...
Grapheme 1: "🤷🏽‍♀️"
(1 grapheme(s) total.)

Кроме того, начиная с .NET 5 метод Microsoft.VisualBasic.Strings.StrReverse, который меняет порядок символов строки в Visual Basic на обратный, также соответствует стандарту Юникода для кластеров графем.

Эти изменения являются частью более обширного набора улучшений для Юникода и UTF-8 в .NET, включая API перечисления расширенных кластеров графем, который дополняет интерфейсы API перечисления скалярных значений Юникода, появившиеся с типом System.Text.Rune в .NET Core 3.0.

Представленные версии

.NET 5.0

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

Затронутые API