Rune Структура

Определение

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

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

Комментарии

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

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

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

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

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

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

Если ваш код выполняет итерацию по char экземплярам в string или 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символом.

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

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

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

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

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

Как создать экземпляр 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. Существуют равнозначные методы чтения с конца диапазона, а не с его начала.

Свойства запроса объекта 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.EncodeToUtf16 преобразует экземпляр Rune в экземпляры 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.EncodeToUtf16 и Rune.EncodeToUtf8 возвращают фактическое количество записанных элементов. Вызывается исключение, если целевой буфер слишком короток, чтобы уместить результат. Существуют невыбрасывающие TryEncodeToUtf8 и TryEncodeToUtf16 методы для вызывающих функций, которые хотят избежать выброса исключений.

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

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

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

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

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

Имя Описание
Rune(Char, Char)

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

Rune(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, StringComparison)

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

Equals(Rune)

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

GetHashCode()

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

GetNumericValue(Rune)

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

GetRuneAt(String, Int32)

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

GetUnicodeCategory(Rune)

Возвращает категорию Юникода, связанную с указанным руном.

IsControl(Rune)

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

IsDigit(Rune)

Возвращает значение, указывающее, классифицируется ли указанный rune как десятичная цифра.

IsLetter(Rune)

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

IsLetterOrDigit(Rune)

Возвращает значение, указывающее, классифицируется ли указанный рун как буква или десятичная цифра.

IsLower(Rune)

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

IsNumber(Rune)

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

IsPunctuation(Rune)

Возвращает значение, указывающее, классифицируется ли указанный 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)

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

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

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

IUtf8SpanParsable<Rune>.Parse(ReadOnlySpan<Byte>, IFormatProvider)

Анализирует диапазон символов UTF-8 в значение.

IUtf8SpanParsable<Rune>.TryParse(ReadOnlySpan<Byte>, IFormatProvider, Rune)

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

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