語言

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>, IParsable<System::Text::Rune>, ISpanFormattable, ISpanParsable<System::Text::Rune>, IUtf8SpanFormattable, IUtf8SpanParsable<System::Text::Rune>
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>, IParsable<System.Text.Rune>, ISpanFormattable, ISpanParsable<System.Text.Rune>, IUtf8SpanFormattable, IUtf8SpanParsable<System.Text.Rune>
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
    interface IFormattable
    interface IParsable<Rune>
    interface ISpanFormattable
    interface ISpanParsable<Rune>
    interface IUtf8SpanFormattable
    interface IUtf8SpanParsable<Rune>
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), IParsable(Of Rune), ISpanFormattable, ISpanParsable(Of Rune), IUtf8SpanFormattable, IUtf8SpanParsable(Of Rune)
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)內的碼點。 型態的建構子與轉換運算子會驗證輸入,因此消費者可以假設底層 Rune 實例是良好形式而呼叫 API。

如果您不熟悉 Unicode 純量值、碼位、代理範圍和格式正確性,請參閱 .NET 中的字元編碼簡介。

使用 Rune 類型的時機

如果您的程式代碼滿足Rune類型,請考慮使用:

  • 呼叫需要 Unicode 純量值的 API
  • 明確處理代理字組

需要 Unicode 純量值的 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 文字傳回不正確結果的原因是,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

明確處理代理字組的程序代碼

如果您的程式碼呼叫明確在代理碼位上操作的 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 相符的匹配項目
  • 在已知的 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 實例也可以從現有的輸入序列讀取。 例如,假設有 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)

類型上 char 可用的許多靜態 API 也可用於 Rune 類型。 例如, Rune.IsWhiteSpace 和 Rune.GetUnicodeCategory 相當於 Char.IsWhiteSpace 和 Char.GetUnicodeCategory 方法。 Rune方法可正確處理 Surrogate 字組。

下列範例程式碼會接受 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 和 Rune 之間有一些 API 差異。 例如:

將Rune轉換為UTF-8或UTF-16

Rune由於 是 Unicode 純量值,因此可以轉換成 UTF-8、UTF-16 或 UTF-32 編碼。 此 Rune 類型內建支持轉換成UTF-8和UTF-16。

Rune.EncodeToUtf16 將 Rune 實例轉換成 char 實例。 若要查詢將 char 實例轉換成 UTF-16 所產生的實例數目,請使用 Rune 屬性。 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 方法。

.NET 中的 Rune 與其他語言

“rune” 一詞未定義於 Unicode 標準中。 此詞彙可追溯到 UTF-8的建立。 羅布·派克和肯·湯普森正在尋找一個詞彙,以描述最終會被稱為代碼點的內容。 他們最終定名為「符文」,而 Rob Pike 後來對 Go 程式語言的影響,幫助這個詞的普及。

不過,.NET Rune 類型與 Go rune 類型不相等。 在 Go 中,rune 類型是 int32 的 別名。 Go rune 的目的是要代表 Unicode 字碼點,但它可以是任何 32 位值,包括代理字碼點和不是合法 Unicode 字碼點的值。

如需其他程式設計語言中的類似類型,請參閱 Rust 的基本 char 類型 或 Swift Unicode.Scalar 的類型,這兩者都代表 Unicode 純量值。 它們提供的功能與 .NET 的 Rune 類型相似,並且禁止實例化非合法的 Unicode 純量值。

建構函式

名稱 Description
Rune(Char, Char)

從提供的 UTF-16 代理節點建立 a Rune 。

Rune(Char)

從提供的 UTF-16 編碼單元建立 a Rune 。

Rune(Int32)

從指定的 32 位元整數產生 a Rune ,該整數代表 Unicode 純量值。

Rune(UInt32)

從指定的 32 位元無符號整數產生 , Rune 該整數代表 Unicode 標量值。

屬性

名稱 Description
IsAscii

會得到一個值,表示與此 Rune 相關值的純量值是否在 ASCII 編碼範圍內。

IsBmp

會得到一個值,表示與此 Rune 相關值是否在 BMP 編碼範圍內。

Plane

取得包含此標量的 Unicode 平面(0 到 16)。

ReplacementChar

會得到 Rune 一個代表 Unicode 替換字元 U+FFFD 的實例。

Utf16SequenceLength

取得UTF-16序列中用來表示此純量值所需的碼單位(碼單位Char)長度。

Utf8SequenceLength

取得UTF-8序列中用來表示此標量值所需的碼單位長度。

Value

會以整數形式取得 Unicode 標量值。

方法

名稱 Description
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)

回傳一個值,表示當前實例與指定符文是否相等。

GetHashCode()

傳回這個實例的哈希碼。

GetNumericValue(Rune)

取得與指定符文相關的數值。

GetRuneAt(String, Int32)

得到 Rune 從字串中指定位置開始的 。

GetUnicodeCategory(Rune)

取得與指定符文相關的 Unicode 類別。

IsControl(Rune)

回傳一個值,表示指定的符文是否被歸類為控制字元。

IsDigit(Rune)

回傳一個值,表示指定的符文是否被分類為十進位數字。

IsLetter(Rune)

回傳一個值,指示指定的符文是否被歸類為字母。

IsLetterOrDigit(Rune)

回傳一個值,指示指定的符文是字母還是十進位數字。

IsLower(Rune)

回傳一個值,指示指定的符文是否屬於小寫字母。

IsNumber(Rune)

回傳一個值,指示指定的符文是否被分類為數字。

IsPunctuation(Rune)

回傳一個值,指示該符文是否屬於標點符號。

IsSeparator(Rune)

回傳一個值,表示指定的符文是否被歸類為分隔符。

IsSymbol(Rune)

回傳一個值,指示該符文是否被歸類為符號字元。

IsUpper(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)

回傳一個值,表示指定的符文是否被歸類為空白字元。

ToLower(Rune, CultureInfo)

回傳一份已轉換為小寫的指定 Rune 副本,並依照指定文化的格式規則。

ToLowerInvariant(Rune)

回傳 Rune 指定副本,經改寫為小寫,使用不變培養的格式化規則。

ToLowerOrdinal(Rune)

代表 Unicode 純量值 ([ U+0000..U+D7FF ], 包含; 或 [ U+E000..U+10FFFF ], 包含)。

ToString()

回傳此 Rune 實例的字串表示。

ToUpper(Rune, CultureInfo)

回傳一份已轉換為大寫的指定 Rune 文化副本,並依照指定文化的大小寫規則。

ToUpperInvariant(Rune)

回傳指定檔案的複製 Rune 品,並依照不變培養的寫字規則轉換為大寫字母。

ToUpperOrdinal(Rune)

代表 Unicode 純量值 ([ U+0000..U+D7FF ], 包含; 或 [ U+E000..U+10FFFF ], 包含)。

TryCreate(Char, Char, Rune)

嘗試從指定的 UTF-16 代理對建立 , Rune 並回傳一個值,表示操作是否成功。

TryCreate(Char, Rune)

嘗試從指定字元建立 , Rune 並回傳一個值,表示操作是否成功。

TryCreate(Int32, Rune)

嘗試從指定有符號整數建立 , Rune 該整數代表 Unicode 純量值。

TryCreate(UInt32, Rune)

嘗試從指定的 32 位元無符號整數(代表 Unicode 純量值)中建立 。Rune

TryEncodeToUtf16(Span<Char>, Int32)

將此 Rune 編碼為 UTF-16 編碼的目的緩衝區。

TryEncodeToUtf8(Span<Byte>, Int32)

將此 Rune 編碼為 UTF-8 編碼的目的緩衝區。

TryGetRuneAt(String, Int32, Rune)

嘗試取得 Rune 從字串指定位置開始的 ,並回傳一個表示操作是否成功的值。

運算子

名稱 Description
Equality(Rune, Rune)

回傳一個表示兩個 Rune 實例是否相等的值。

Explicit(Char to Rune)

定義了將 16 位元 Unicode 字元 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。

明確介面實作

名稱 Description
IComparable.CompareTo(Object)

將目前實例與指定的物件進行比較。

IFormattable.ToString(String, IFormatProvider)

使用指定的格式,格式化目前實例的值。

IParsable<Rune>.Parse(String, IFormatProvider)

代表 Unicode 純量值 ([ U+0000..U+D7FF ], 包含; 或 [ U+E000..U+10FFFF ], 包含)。

IParsable<Rune>.TryParse(String, IFormatProvider, Rune)

代表 Unicode 純量值 ([ U+0000..U+D7FF ], 包含; 或 [ U+E000..U+10FFFF ], 包含)。

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

嘗試將目前實例的值格式化為提供的字元範圍。

ISpanParsable<Rune>.Parse(ReadOnlySpan<Char>, IFormatProvider)

代表 Unicode 純量值 ([ U+0000..U+D7FF ], 包含; 或 [ U+E000..U+10FFFF ], 包含)。

ISpanParsable<Rune>.TryParse(ReadOnlySpan<Char>, IFormatProvider, Rune)

代表 Unicode 純量值 ([ U+0000..U+D7FF ], 包含; 或 [ U+E000..U+10FFFF ], 包含)。

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 ], 包含)。

適用於