Rune 结构

定义

表示 Unicode 标量值 ([ 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 实例表示 Unicode 标量值,即除代理范围 (U+D800..U+DFFF) 之外的任何代码点。 该类型的构造函数和转换运算符验证输入,因此使用者可以调用 API(假设基础 Rune 实例格式良好)。

如果对 Unicode 标量值、码点、代理范围和良好格式化等术语不熟悉,请参阅 .NET 中的字符编码简介

何时使用 Rune 类型

如果你的代码符合以下条件,请考虑使用Rune类型:

  • 调用需要 Unicode 标量值的 API
  • 显式处理代理对

需要 Unicode 标量值的 API

如果代码遍历 char 实例中的 stringReadOnlySpan<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

但对于基本多语言平面之外的语言,如奥萨奇语,它将无法正常工作:

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

该方法对奥萨奇文本返回错误结果的原因是,奥萨奇字母中的 char 实例是代理码点。 没有单个代理项代码点有足够的信息来确定它是否为字母。

如果将此代码更改为使用 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;
}

前面的代码正确地计算了奥塞奇字母的数量。

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

显示处理代理对的代码

如果代码调用显式处理代理代码点的 API,请考虑使用 Rune 类型,例如以下方法:

例如,以下方法具有处理代理 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 的完全匹配
  • 在已知字符值上拆分字符串

使用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 实例表示 Unicode 标量值,因此遵循 Unicode 文本分段准则的 组件可以用作 Rune 计算显示字符的构建基块。

StringInfo 类型可用于对显示字符进行计数,但在除 .NET 5+ 以外的 .NET 实现的所有方案中,该类型不会正确计数。

有关详细信息,请参阅 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
    

如果输入不表示有效的 Unicode 标量值,则所有构造函数都会引发 ArgumentException

对于不希望在失败时引发异常的调用方,有 Rune.TryCreate 种方法可用。

Rune 实例也可以从现有输入序列中读取。 例如,给定一个表示 UTF-16 数据的 ReadOnlySpan<char>Rune.DecodeFromUtf16 方法返回输入范围开头的第一个 Rune 实例。 Rune.DecodeFromUtf8 方法以相似的方式操作,接受一个表示 UTF-8 数据的 ReadOnlySpan<byte> 参数。 存在与从跨度末尾读取数据而非从跨度开头读取数据等效的方法。

查询Rune的属性

若要获取实例的 Rune 整数代码点值,请使用 Rune.Value 该属性。

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

char类型上提供的许多静态 API 也可用于Rune类型。 例如,Rune.IsWhiteSpaceRune.GetUnicodeCategory 等效于 Char.IsWhiteSpaceChar.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;
}

charRune之间存在一些API差异。 例如:

Rune 转换为 UTF-8 或 UTF-16

由于 a Rune 是 Unicode 标量值,因此可以转换为 UTF-8、UTF-16 或 UTF-32 编码。 该 Rune 类型具有对转换为 UTF-8 和 UTF-16 的内置支持。

Rune.EncodeToUtf16实例转换为Runechar实例。 若要查询通过将 char 实例转换为 UTF-16 后生成的 Rune 实例数,请使用 Rune.Utf16SequenceLength 属性。 类似的方法用于 UTF-8 转换。

以下示例将 Rune 实例转换为 char 数组。 代码假定你在Rune变量中有一个rune实例。

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

由于 a 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.EncodeToUtf16Rune.EncodeToUtf8方法返回写入的实际元素数。 如果目标缓冲区太短而无法包含结果,则会引发异常。 对于希望避免异常的调用方,还提供了不引发异常的 TryEncodeToUtf8TryEncodeToUtf16 方法。

.NET 中的 Rune 与其他语言的比较

“rune”一词在 Unicode 标准中并未定义。 该术语可追溯到 UTF-8 的创建。 Rob Pike 和 Ken Thompson 正在寻找一个术语来描述最终被称为代码点的内容。 他们确定了术语“rune”,罗布·派克后来对 Go 编程语言的影响有助于推广这个词。

但是,.NET Rune 类型与 Go rune 类型不相等。 在 Go 中,rune 类型是 的别名,用于表示 int32。 Go rune 旨在表示 Unicode 码位,但它可以是任何 32 位值,包括代理代码点和不是合法 Unicode 码位的值。

有关其他编程语言中的类似类型,请参阅 Rust 的基元 char 类型Swift Unicode.Scalar 的类型,这两种类型都表示 Unicode 标量值。 它们提供的功能类似于 .NET 的类型 Rune ,不允许实例化非合法 Unicode 标量值的值。

构造函数

名称 说明
Rune(Char, Char)

从提供的 UTF-16 代理项对创建一个 Rune

Rune(Char)

从提供的 UTF-16 代码单元创建一个 Rune

Rune(Int32)

Rune从表示 Unicode 标量值的指定 32 位整数创建一个。

Rune(UInt32)

Rune从表示 Unicode 标量值的指定 32 位无符号整数创建一个。

属性

名称 说明
IsAscii

获取一个值,该值指示与此 Rune 关联的标量值是否在 ASCII 编码范围内。

IsBmp

获取一个值,该值指示与此 Rune 关联的标量值是否在 BMP 编码范围内。

Plane

获取包含此标量的 Unicode 平面(0 到 16(含)。

ReplacementChar

获取表示 Rune Unicode 替换字符 U+FFFD 的实例。

Utf16SequenceLength

获取表示此标量值所需的 UTF-16 序列的代码单位(以代码单位为单位Char)。

Utf8SequenceLength

获取表示此标量值所需的 UTF-8 序列的代码单位的长度。

Value

获取 Unicode 标量值作为整数。

方法

名称 说明
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)

表示 Unicode 标量值 ([ U+0000..U+D7FF ], 非独占; 或 [ U+E000..U+10FFFF ],含)。

Equals(Rune)

返回一个值,该值指示当前实例和指定的 rune 是否相等。

GetHashCode()

返回此实例的哈希代码。

GetNumericValue(Rune)

获取与指定 rune 关联的数值。

GetRuneAt(String, Int32)

Rune获取从字符串中的指定位置开始的函数。

GetUnicodeCategory(Rune)

获取与指定 rune 关联的 Unicode 类别。

IsControl(Rune)

返回一个值,该值指示指定的 Rune 是否分类为控制字符。

IsDigit(Rune)

返回一个值,该值指示指定的 rune 是否分类为十进制数字。

IsLetter(Rune)

返回一个值,该值指示指定的 Rune 是否分类为字母。

IsLetterOrDigit(Rune)

返回一个值,该值指示指定的 rune 是分类为字母还是十进制数字。

IsLower(Rune)

返回一个值,该值指示指定的 Rune 是否分类为小写字母。

IsNumber(Rune)

返回一个值,该值指示指定的 Rune 是否分类为数字。

IsPunctuation(Rune)

返回一个值,该值指示指定的 rune 是否被分类为标点符号。

IsSeparator(Rune)

返回一个值,该值指示指定的 rune 是否分类为分隔符。

IsSymbol(Rune)

返回一个值,该值指示指定的 rune 是否分类为符号字符。

IsUpper(Rune)

返回一个值,该值指示指定的 rune 是否分类为大写字母。

IsValid(Int32)

返回一个值,该值指示 32 位有符号整数是否表示有效的 Unicode 标量值;也就是说,它位于 [U+0000..U+D7FF ], 非独占;或 [ U+E000..U+10FFFF ],非独占。

IsValid(UInt32)

返回一个值,该值指示 32 位无符号整数是否表示有效的 Unicode 标量值;也就是说,它位于 [U+0000..U+D7FF ]、非独占或 [U+E000.. 范围内。U+10FFFF ],非独占。

IsWhiteSpace(Rune)

返回一个值,该值指示指定的 rune 是否分类为空白字符。

ToLower(Rune, CultureInfo)

使用指定区域性的大小写规则返回指定转换为小写的指定副本 Rune

ToLowerInvariant(Rune)

返回使用固定区域性的大小写规则转换为小写的指定 Rune 副本。

ToString()

返回此 Rune 实例的字符串表示形式。

ToUpper(Rune, CultureInfo)

使用指定区域性的大小写规则返回指定转换为大写的指定副本 Rune

ToUpperInvariant(Rune)

返回使用固定区域性的大小写规则转换为大写的指定 Rune 副本。

TryCreate(Char, Char, Rune)

尝试从指定的 UTF-16 代理项对创建一个 Rune ,并返回一个值,该值指示操作是否成功。

TryCreate(Char, Rune)

尝试从指定的字符创建一个 Rune 值,并返回一个值,该值指示操作是否成功。

TryCreate(Int32, Rune)

尝试从表示 Unicode 标量值的指定带符号整数创建 Rune 一个。

TryCreate(UInt32, Rune)

尝试从表示 Unicode 标量值的指定 32 位无符号整数创建 Rune 一个。

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 位 Unicode 字符到 a 的 Rune显式转换。

Explicit(Int32 to Rune)

定义 32 位有符号整数到 a Rune的显式转换。

Explicit(UInt32 to Rune)

定义 32 位无符号整数到 a 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)

表示 Unicode 标量值 ([ U+0000..U+D7FF ], 非独占; 或 [ U+E000..U+10FFFF ],含)。

适用于