Rune Структура

Определение

Представляет скалярное значение Юникода ([U+0000.. U+D7FF] включительно или [U+E000..U+10FFFF] включительно).

public value class Rune : IComparable, IComparable<System::Text::Rune>, IEquatable<System::Text::Rune>
public value class Rune : IComparable, IComparable<System::Text::Rune>, IEquatable<System::Text::Rune>, ISpanFormattable
public value class Rune : IComparable<System::Text::Rune>, IEquatable<System::Text::Rune>
public readonly struct Rune : IComparable, IComparable<System.Text.Rune>, IEquatable<System.Text.Rune>
public readonly struct Rune : IComparable, IComparable<System.Text.Rune>, IEquatable<System.Text.Rune>, ISpanFormattable
public readonly struct Rune : IComparable<System.Text.Rune>, IEquatable<System.Text.Rune>
type Rune = struct
type Rune = struct
    interface ISpanFormattable
    interface IFormattable
type Rune = struct
    interface IFormattable
    interface ISpanFormattable
Public Structure Rune
Implements IComparable, IComparable(Of Rune), IEquatable(Of Rune)
Public Structure Rune
Implements IComparable, IComparable(Of Rune), IEquatable(Of Rune), ISpanFormattable
Public Structure Rune
Implements IComparable(Of Rune), IEquatable(Of Rune)
Наследование
Реализации

Комментарии

Rune Экземпляр представляет скалярное значение Юникода, что означает любую кодовую точку, за исключением суррогатного диапазона (U+D800.). U+DFFF). Конструкторы и операторы преобразования типа проверяют входные данные, поэтому потребители могут вызывать API, предполагая, что базовый Rune экземпляр правильно сформирован.

Если вы не знакомы с терминами Юникод скалярное значение, кодовая точка, суррогатный диапазон и хорошо сформированный диапазон, см. общие сведения о кодировке символов в .NET.

В следующих разделах объясняется следующее:

Когда следует использовать тип Rune

Рассмотрите возможность использования типа, Rune если код:

  • Вызывает API- интерфейсы, требующие скалярных значений Юникода
  • Явным образом обрабатывает суррогатные пары

API, требующие скалярных значений Юникода

Если код выполняет итерацию по char экземплярам в a string или a ReadOnlySpan<char>, некоторые char методы не будут работать правильно с char экземплярами, которые находятся в суррогатном диапазоне. Например, для правильной работы следующих API-интерфейсов требуется скалярное значение char :

В следующем примере показан код, который не будет работать правильно, если какие-либо из char экземпляров являются суррогатными кодовых точками:

// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
int CountLettersBadExample(string s)
{
    int letterCount = 0;

    foreach (char ch in s)
    {
        if (char.IsLetter(ch))
        { letterCount++; }
    }

    return letterCount;
}
// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
let countLettersBadExample (s: string) =
    let mutable letterCount = 0

    for ch in s do
        if Char.IsLetter ch then
            letterCount <- letterCount + 1
    
    letterCount

Ниже приведен эквивалентный код, который работает со ReadOnlySpan<char>следующим кодом:

// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
static int CountLettersBadExample(ReadOnlySpan<char> span)
{
    int letterCount = 0;

    foreach (char ch in span)
    {
        if (char.IsLetter(ch))
        { letterCount++; }
    }

    return letterCount;
}

Приведенный выше код работает правильно с некоторыми языками, такими как английский:

CountLettersInString("Hello")
// Returns 5

Но он не будет работать правильно для языков за пределами базовой многоязычной плоскости, например Osage:

CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 0

Причина, по которой этот метод возвращает неверные результаты для текста Osage, заключается в том, что char экземпляры букв Osage являются суррогатными кодовых точками. Ни одна суррогатная кодовая точка не имеет достаточно информации, чтобы определить, является ли это буквой.

Если вместо этого изменить этот код Rune char, метод работает правильно с кодными точками за пределами базовой многоязычной плоскости:

int CountLetters(string s)
{
    int letterCount = 0;

    foreach (Rune rune in s.EnumerateRunes())
    {
        if (Rune.IsLetter(rune))
        { letterCount++; }
    }

    return letterCount;
}
let countLetters (s: string) =
    let mutable letterCount = 0

    for rune in s.EnumerateRunes() do
        if Rune.IsLetter rune then
            letterCount <- letterCount + 1

    letterCount

Ниже приведен эквивалентный код, который работает со ReadOnlySpan<char>следующим кодом:

static int CountLetters(ReadOnlySpan<char> span)
{
    int letterCount = 0;

    foreach (Rune rune in span.EnumerateRunes())
    {
        if (Rune.IsLetter(rune))
        { letterCount++; }
    }

    return letterCount;
}

Приведенный выше код правильно подсчитывает буквы Osage:

CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 8

Код, который явно обрабатывает суррогатные пары

Рассмотрите Rune возможность использования типа, если код вызывает API, которые явно работают с суррогатными кодными точками, такими как следующие методы:

Например, следующий метод имеет специальную логику для решения суррогатных char пар:

static void ProcessStringUseChar(string s)
{
    Console.WriteLine("Using char");

    for (int i = 0; i < s.Length; i++)
    {
        if (!char.IsSurrogate(s[i]))
        {
            Console.WriteLine($"Code point: {(int)(s[i])}");
        }
        else if (i + 1 < s.Length && char.IsSurrogatePair(s[i], s[i + 1]))
        {
            int codePoint = char.ConvertToUtf32(s[i], s[i + 1]);
            Console.WriteLine($"Code point: {codePoint}");
            i++; // so that when the loop iterates it's actually +2
        }
        else
        {
            throw new Exception("String was not well-formed UTF-16.");
        }
    }
}

Такой код проще использовать Rune, как показано в следующем примере:

static void ProcessStringUseRune(string s)
{
    Console.WriteLine("Using Rune");

    for (int i = 0; i < s.Length;)
    {
        if (!Rune.TryGetRuneAt(s, i, out Rune rune))
        {
            throw new Exception("String was not well-formed UTF-16.");
        }

        Console.WriteLine($"Code point: {rune.Value}");
        i += rune.Utf16SequenceLength; // increment the iterator by the number of chars in this Rune
    }
}

Когда не следует использовать Rune

Не нужно использовать тип, Rune если код:

  • Поиск точных char совпадений
  • Разбивает строку на известное значение char

Использование типа может возвращать неверные Rune результаты, если код:

  • Подсчитывает количество отображаемых символов в string

Поиск точных char совпадений

Следующий код выполняет итерации по поиску string определенных символов, возвращая индекс первого совпадения. Изменить этот код для использования Runeне нужно, так как код ищет символы, представленные одним charсимволом.

int GetIndexOfFirstAToZ(string s)
{
    for (int i = 0; i < s.Length; i++)
    {
        char thisChar = s[i];
        if ('A' <= thisChar && thisChar <= 'Z')
        {
            return i; // found a match
        }
    }

    return -1; // didn't find 'A' - 'Z' in the input string
}

Разделение строки на известном char

Обычно можно вызывать string.Split и использовать разделители, такие как ' ' (пробел) или ',' (запятая), как показано в следующем примере:

string inputString = "🐂, 🐄, 🐆";
string[] splitOnSpace = inputString.Split(' ');
string[] splitOnComma = inputString.Split(',');

Здесь нет необходимости использовать Rune , так как код ищет символы, представленные одним charсимволом.

Подсчет количества отображаемых символов в a string

Число Rune экземпляров в строке может не соответствовать числу символов, отображаемых при отображении строки.

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

Тип StringInfo можно использовать для подсчета отображаемых символов, но он не учитывается правильно во всех сценариях для реализаций .NET, отличных от .NET 5+.

Дополнительные сведения см. в разделе "Кластеры Grapheme".

Создание экземпляра a Rune

Существует несколько способов получения экземпляра Rune . Конструктор можно использовать для создания непосредственно из Rune :

  • Кодовая точка.

    Rune a = new Rune(0x0061); // LATIN SMALL LETTER A
    Rune b = new Rune(0x10421); // DESERET CAPITAL LETTER ER
    
  • Один файл char.

    Rune c = new Rune('a');
    
  • Суррогатная char пара.

    Rune d = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
    

Все конструкторы создают исключение, ArgumentException если входные данные не представляют допустимое скалярное значение Юникода.

Существуют методы, доступные Rune.TryCreate для вызывающих лиц, которые не хотят создавать исключения при сбое.

Rune экземпляры также можно считывать из существующих входных последовательностей. Например, учитывая ReadOnlySpan<char> , что представляет данные UTF-16, Rune.DecodeFromUtf16 метод возвращает первый Rune экземпляр в начале входного диапазона. Метод Rune.DecodeFromUtf8 работает аналогичным образом, принимая ReadOnlySpan<byte> параметр, представляющий данные UTF-8. Существуют эквивалентные методы для считывания с конца диапазона вместо начала диапазона.

Свойства запроса объекта a Rune

Чтобы получить целочисленное значение кодовой точки экземпляра Rune , используйте Rune.Value свойство.

Rune rune = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
int codePoint = rune.Value; // = 128302 decimal (= 0x1F52E)

Многие статические API, доступные в типе char , также доступны в типе Rune . Например, Rune.IsWhiteSpace это Rune.GetUnicodeCategory эквиваленты Char.IsWhiteSpace и Char.GetUnicodeCategory методы. Методы Rune правильно обрабатывают суррогатные пары.

В следующем примере кода в качестве входных данных и обрезок от начального и конца диапазона принимается ReadOnlySpan<char> не Rune буква или цифра.

static ReadOnlySpan<char> TrimNonLettersAndNonDigits(ReadOnlySpan<char> span)
{
    // First, trim from the front.
    // If any Rune can't be decoded
    // (return value is anything other than "Done"),
    // or if the Rune is a letter or digit,
    // stop trimming from the front and
    // instead work from the end.
    while (Rune.DecodeFromUtf16(span, out Rune rune, out int charsConsumed) == OperationStatus.Done)
    {
        if (Rune.IsLetterOrDigit(rune))
        { break; }
        span = span[charsConsumed..];
    }

    // Next, trim from the end.
    // If any Rune can't be decoded,
    // or if the Rune is a letter or digit,
    // break from the loop, and we're finished.
    while (Rune.DecodeLastFromUtf16(span, out Rune rune, out int charsConsumed) == OperationStatus.Done)
    {
        if (Rune.IsLetterOrDigit(rune))
        { break; }
        span = span[..^charsConsumed];
    }

    return span;
}

Существуют некоторые различия между char API и Rune. Пример:

Rune Преобразование в UTF-8 или UTF-16

Rune Так как это скалярное значение Юникода, его можно преобразовать в кодировку UTF-8, UTF-16 или UTF-32. Тип Rune имеет встроенную поддержку преобразования в UTF-8 и UTF-16.

Rune Преобразует Rune.EncodeToUtf16 экземпляр char в экземпляры. Чтобы запросить количество экземпляров char , которые будут результатом преобразования экземпляра Rune в UTF-16, используйте Rune.Utf16SequenceLength это свойство. Аналогичные методы существуют для преобразования UTF-8.

В следующем примере экземпляр преобразуется Rune в char массив. В коде предполагается, что у вас есть Rune экземпляр в переменной rune :

char[] chars = new char[rune.Utf16SequenceLength];
int numCharsWritten = rune.EncodeToUtf16(chars);

string Так как это последовательность символов UTF-16, следующий пример также преобразует экземпляр в Rune UTF-16:

string theString = rune.ToString();

В следующем примере экземпляр преобразуется Rune в UTF-8 массив байтов:

byte[] bytes = new byte[rune.Utf8SequenceLength];
int numBytesWritten = rune.EncodeToUtf8(bytes);

Rune.EncodeToUtf8 Методы Rune.EncodeToUtf16 возвращают фактическое количество записанных элементов. Они вызывают исключение, если целевой буфер слишком короткий, чтобы содержать результат. Существуют неотбрасывание TryEncodeToUtf8 и EncodeToUtf16 методы, а также для вызывающих лиц, желающих избежать исключений.

Rune в .NET и других языках

Термин "rune" не определен в стандарте Юникода. Термин восходит к созданию UTF-8. Роб Пайк и Кен Томпсон искали термин, чтобы описать, что в конечном итоге станет известной как кодовая точка. Они поселились на термине "руна", и позднее влияние Роба Пайка на язык программирования Go помогло популяризировать термин.

Однако тип .NET Rune не является эквивалентом типа Go rune . В Go rune тип является псевдонимом для int32. Руно Go предназначено для представления кодовой точки Юникода, но это может быть любое 32-разрядное значение, включая суррогатные кодовые точки и значения, которые не являются законными кодовых точек Юникода.

Аналогичные типы в других языках программирования см. в разделе "Примитивный char тип Rust" или "Тип SwiftUnicode.Scalar", оба из которых представляют скалярные значения Юникода. Они предоставляют функциональные возможности, аналогичные . Rune Тип NET, и они запрещают создание экземпляров значений, которые не являются законными скалярными значениями Юникода.

Конструкторы

Rune(Char)

Создает объект Rune из предоставленного блока кода UTF-16.

Rune(Char, Char)

Создает объект Rune из предоставленной суррогатной пары UTF-16.

Rune(Int32)

Создает Rune из указанного 32-разрядного целого числа, представляющего скалярное значение Юникода.

Rune(UInt32)

Создает Rune из указанного 32-разрядного целого числа без знака, представляющего скалярное значение Юникода.

Свойства

IsAscii

Возвращает значение, указывающее, находится ли скалярное значение, связанное с этим Rune, в диапазоне кодирования ASCII.

IsBmp

Возвращает значение, указывающее, находится ли скалярное значение, связанное с этим Rune, в диапазоне кодирования BMP.

Plane

Возвращает плоскость Юникода (от 0 до 16 включительно), которая содержит этот скаляр.

ReplacementChar

Возвращает экземпляр Rune, представляющий символ замены Юникода U+FFFD.

Utf16SequenceLength

Возвращает длину в блоках кода (Char) для последовательности UTF-16, которая должна представлять это скалярное значение.

Utf8SequenceLength

Возвращает длину в блоках для последовательности UTF-8, которая должна представлять это скалярное значение.

Value

Возвращает скалярное значение Юникода в виде целого числа.

Методы

CompareTo(Rune)

Сравнивает текущий экземпляр с указанным экземпляром Rune.

DecodeFromUtf16(ReadOnlySpan<Char>, Rune, Int32)

Декодирует в Rune начале предоставленного исходного буфера UTF-16.

DecodeFromUtf8(ReadOnlySpan<Byte>, Rune, Int32)

Декодирует в Rune начале предоставленного исходного буфера UTF-8.

DecodeLastFromUtf16(ReadOnlySpan<Char>, Rune, Int32)

Декодирует Rune в конце предоставленного исходного буфера UTF-16.

DecodeLastFromUtf8(ReadOnlySpan<Byte>, Rune, Int32)

Декодирует Rune в конце предоставленного исходного буфера UTF-8.

EncodeToUtf16(Span<Char>)

Кодирует это Rune в буфер назначения UTF-16.

EncodeToUtf8(Span<Byte>)

Кодирует это Rune в буфер назначения UTF-8.

Equals(Object)

Возвращает значение, указывающее, равен ли данный экземпляр указанному объекту.

Equals(Rune)

Возвращает значение, указывающее, равен ли данный экземпляр указанной руне.

GetHashCode()

Возвращает хэш-код данного экземпляра.

GetNumericValue(Rune)

Получает числовое значение, связанное с указанной руной.

GetRuneAt(String, Int32)

Возвращает объект Rune, начинающийся с указанной позиции в строке.

GetUnicodeCategory(Rune)

Получает категорию Юникода, связанную с указанной руной.

IsControl(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории управляющих символов.

IsDigit(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории десятичных чисел.

IsLetter(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории букв.

IsLetterOrDigit(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории букв или десятичных чисел.

IsLower(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории букв нижнего регистра.

IsNumber(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории цифр.

IsPunctuation(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории знаков препинания.

IsSeparator(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории знаков разделения.

IsSymbol(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории знаков символов.

IsUpper(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории букв верхнего регистра.

IsValid(Int32)

Возвращает значение, указывающее, представляет ли 32-разрядное целое число со знаком допустимое скалярное значение Юникода, то есть находится ли оно в диапазоне [U+0000..U+D7FF] включительно или [U+ E000..U+10FFFF] включительно.

IsValid(UInt32)

Возвращает значение, указывающее, представляет ли 32-разрядное целое число без знака допустимое скалярное значение Юникода, то есть находится ли оно в диапазоне [U+0000..U+D7FF] включительно или [U+ E000..U+10FFFF] включительно.

IsWhiteSpace(Rune)

Возвращает значение, которое показывает, относится ли указанная руна к категории пробелов.

ToLower(Rune, CultureInfo)

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

ToLowerInvariant(Rune)

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

ToString()

Возвращает строковое представление этого экземпляра Rune.

ToUpper(Rune, CultureInfo)

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

ToUpperInvariant(Rune)

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

TryCreate(Char, Char, Rune)

Пытается создать Rune из указанной суррогатной пары в UTF-16 и возвращает значение, указывающее, успешно ли выполнена операция.

TryCreate(Char, Rune)

Пытается создать Rune из указанного символа и возвращает значение, указывающее, успешно ли выполнена операция.

TryCreate(Int32, Rune)

Пытается создать Rune из указанного целого числа со знаком, представляющего скалярное значение Юникода.

TryCreate(UInt32, Rune)

Пытается создать Rune из указанного целого 32-разрядного числа без знака, представляющего скалярное значение Юникода.

TryEncodeToUtf16(Span<Char>, Int32)

Кодирует это Rune в буфер назначения в кодировке UTF-16.

TryEncodeToUtf8(Span<Byte>, Int32)

Кодирует это Rune в буфер назначения в кодировке UTF-8.

TryGetRuneAt(String, Int32, Rune)

Пытается получить объект Rune, начинающийся с указанной позиции в строке, и возвращает значение, указывающее, завершилась ли операция успехом.

Операторы

Equality(Rune, Rune)

Возвращает значение, указывающее, равны ли два экземпляра Rune.

Explicit(Char to Rune)

Определяет явное преобразование 16-разрядного символа Юникода в Rune.

Explicit(Int32 to Rune)

Определяет явное преобразование 32-разрядного целого числа со знаком в значение Rune.

Explicit(UInt32 to Rune)

Определяет явное преобразование 32-разрядного целого числа без знака в значение Rune.

GreaterThan(Rune, Rune)

Возвращает значение, позволяющее определить, действительно ли заданное значение типа Rune больше другого заданного значения типа Rune.

GreaterThanOrEqual(Rune, Rune)

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

Inequality(Rune, Rune)

Возвращает значение, указывающее, различаются ли значения двух экземпляров Rune.

LessThan(Rune, Rune)

Возвращает значение, позволяющее определить, действительно ли заданное значение типа Rune меньше другого заданного значения типа Rune.

LessThanOrEqual(Rune, Rune)

Возвращает значение, позволяющее определить, действительно ли заданное значение типа Rune меньше или равно другому заданному значению типа Rune.

Явные реализации интерфейса

IComparable.CompareTo(Object)

Сравнивает текущий экземпляр с указанным объектом.

IFormattable.ToString(String, IFormatProvider)

Форматирует значение текущего экземпляра, используя указанный формат.

ISpanFormattable.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)

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

Применяется к