System.Text.Rune-Struktur
Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.
Eine Rune Instanz stellt einen Unicode-Skalarwert dar, was bedeutet, dass ein beliebiger Codepunkt mit Ausnahme des Ersatzbereichs (U+D800.) steht. U+DFFF). Die Konstruktoren und Konvertierungsoperatoren des Typs überprüfen die Eingabe, sodass Verbraucher die APIs aufrufen können, vorausgesetzt, dass die zugrunde liegende Rune Instanz wohlgeformt ist.
Wenn Sie mit den Begriffen Unicode-Skalarwert, Codepunkt, Ersatzbereich und wohlgeformt nicht vertraut sind, lesen Sie die Einführung in die Zeichencodierung in .NET.
Wann der Rune-Typ verwendet werden soll
Erwägen Sie die Verwendung des Typs Rune
, wenn Ihr Code:
- Ruft APIs auf, die Unicode-Skalarwerte erfordern
- Behandelt Surrogatepaare explizit
APIs, die Unicode-Skalarwerte erfordern
Wenn Ihr Code die char
Instanzen in einer string
oder einer ReadOnlySpan<char>
Durchlaufen durchläuft, funktionieren einige der char
Methoden nicht ordnungsgemäß für char
Instanzen, die sich im Ersatzbereich befinden. Die folgenden APIs erfordern z. B. einen skalaren Wert char
, um ordnungsgemäß zu funktionieren:
- Char.GetNumericValue
- Char.GetUnicodeCategory
- Char.IsDigit
- Char.IsLetter
- Char.IsLetterOrDigit
- Char.IsLower
- Char.IsNumber
- Char.IsPunctuation
- Char.IsSymbol
- Char.IsUpper
Das folgende Beispiel zeigt Code, der nicht ordnungsgemäß funktioniert, wenn eine der char
Instanzen Surrogate-Codepunkte enthält:
// 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
Hier sehen Sie den entsprechenden Code, der mit einem 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;
}
Der vorangehende Code funktioniert ordnungsgemäß mit einigen Sprachen wie Englisch:
CountLettersInString("Hello")
// Returns 5
Es funktioniert jedoch nicht ordnungsgemäß für Sprachen außerhalb der mehrsprachigen Basisebene, z. B. Osage:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 0
Der Grund, warum diese Methode falsche Ergebnisse für Osage-Text zurückgibt, besteht darin, dass die char
Instanzen für Osage-Buchstaben Surrogate-Codepunkte sind. Kein einzelner Ersatzcodepunkt verfügt über genügend Informationen, um festzustellen, ob es sich um einen Buchstaben handelt.
Wenn Sie diesen Code so ändern, dass er anstelle verwendet char
wirdRune
, funktioniert die Methode ordnungsgemäß mit Codepunkten außerhalb der Mehrsprachigen Standardebene:
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
Hier sehen Sie den entsprechenden Code, der mit einem ReadOnlySpan<char>
:
static int CountLetters(ReadOnlySpan<char> span)
{
int letterCount = 0;
foreach (Rune rune in span.EnumerateRunes())
{
if (Rune.IsLetter(rune))
{ letterCount++; }
}
return letterCount;
}
Der vorangehende Code zählt Osage-Buchstaben richtig:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 8
Code, der Surrogatepaare explizit behandelt
Erwägen Sie die Verwendung des Rune
Typs, wenn Ihr Code APIs aufruft, die explizit auf Surrogate-Codepunkten arbeiten, z. B. die folgenden Methoden:
- Char.IsSurrogate
- Char.IsSurrogatePair
- Char.IsHighSurrogate
- Char.IsLowSurrogate
- Char.ConvertFromUtf32
- Char.ConvertToUtf32
Die folgende Methode hat z. B. spezielle Logik zum Umgang mit Ersatzpaaren 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.");
}
}
}
Dieser Code ist einfacher, wenn er Rune
verwendet wird, wie im folgenden Beispiel:
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
}
}
Ungeeignete Fälle für Rune
Sie müssen den Rune
Typ nicht verwenden, wenn Ihr Code:
- Sucht nach genauen
char
Übereinstimmungen - Teilt eine Zeichenfolge auf einen bekannten Zeichenwert auf.
Die Verwendung des Typs Rune
gibt möglicherweise falsche Ergebnisse zurück, wenn Ihr Code:
- Zählt die Anzahl der Anzeigezeichen in einem
string
Suchen nach exakten char
Übereinstimmungen
Der folgende Code durchläuft eine string
Suche nach bestimmten Zeichen und gibt den Index der ersten Übereinstimmung zurück. Dieser Code Rune
muss nicht geändert werden, da der Code nach Zeichen sucht, die durch einen einzelnen char
dargestellt werden.
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
}
Teilen einer Zeichenfolge auf einer bekannten char
Es ist üblich, Trennzeichen wie ' '
(Leerzeichen) oder ','
(Komma) aufzurufen string.Split
und zu verwenden, wie im folgenden Beispiel:
string inputString = "🐂, 🐄, 🐆";
string[] splitOnSpace = inputString.Split(' ');
string[] splitOnComma = inputString.Split(',');
Hier ist keine Verwendung Rune
erforderlich, da der Code nach Zeichen sucht, die durch einen einzelnen char
dargestellt werden.
Zählen der Anzahl der Anzeigezeichen in einem string
Die Anzahl der Rune
Instanzen in einer Zeichenfolge entspricht möglicherweise nicht der Anzahl von benutzerdefinierten Zeichen, die beim Anzeigen der Zeichenfolge angezeigt werden.
Da Rune
Instanzen Unicode-Skalarwerte darstellen, können Komponenten, die den Unicode-Textsegmentierungsrichtlinien entsprechen, als Baustein für das Zählen von Anzeigezeichen verwendet werden Rune
.
Der StringInfo Typ kann verwendet werden, um Anzeigezeichen zu zählen, jedoch nicht in allen Szenarien für .NET-Implementierungen, die nicht .NET 5+ sind.
Weitere Informationen finden Sie unter Grapheme-Cluster.
Instanziieren eines Rune
Es gibt mehrere Möglichkeiten zum Abrufen einer Rune
Instanz. Sie können einen Konstruktor verwenden, um einen Rune
direkt aus:
Ein Codepunkt.
Rune a = new Rune(0x0061); // LATIN SMALL LETTER A Rune b = new Rune(0x10421); // DESERET CAPITAL LETTER ER
Eine einzelne
char
.Rune c = new Rune('a');
Ein Ersatzpaar
char
.Rune d = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
Alle Konstruktoren lösen einen ArgumentException
Aus, wenn die Eingabe keinen gültigen Unicode-Skalarwert darstellt.
Es stehen Rune.TryCreate Methoden für Aufrufer zur Verfügung, die keine Ausnahmen für Fehler auslösen möchten.
Rune
Instanzen können auch aus vorhandenen Eingabesequenzen gelesen werden. Wenn beispielsweise UTF-16-Daten ReadOnlySpan<char>
dargestellt werden, gibt die Rune.DecodeFromUtf16 Methode die erste Rune
Instanz am Anfang der Eingabespanne zurück. Die Rune.DecodeFromUtf8 Methode funktioniert ähnlich und akzeptiert einen ReadOnlySpan<byte>
Parameter, der UTF-8-Daten darstellt. Es gibt entsprechende Methoden zum Lesen vom Ende der Spanne anstelle des Anfangs der Spanne.
Abfrageeigenschaften eines Rune
Verwenden Sie die Rune.Value Eigenschaft, um den ganzzahligen Codepunktwert einer Rune
Instanz abzurufen.
Rune rune = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
int codePoint = rune.Value; // = 128302 decimal (= 0x1F52E)
Viele der statischen APIs, die für den char
Typ verfügbar sind, sind auch für den Rune
Typ verfügbar. Beispielsweise Rune.IsWhiteSpace sind sie Rune.GetUnicodeCategory Entsprechungen Char.IsWhiteSpace und Char.GetUnicodeCategory Methoden. Die Rune
Methoden behandeln Ersatzpaare richtig.
Der folgende Beispielcode verwendet eine ReadOnlySpan<char>
Eingabe und schneidet sowohl vom Anfang als auch vom Ende der Spanne ab Rune
, bei der es sich nicht um einen Buchstaben oder eine Ziffer handelt.
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;
}
Es gibt einige API-Unterschiede zwischen char
und Rune
. Beispiel:
- Es gibt keine
Rune
Entsprechung zu Char.IsSurrogate(Char), daRune
Instanzen per Definition niemals Ersatzcodepunkte sein können. - Das Rune.GetUnicodeCategory Ergebnis gibt nicht immer dasselbe Ergebnis wie Char.GetUnicodeCategory. Er gibt denselben Wert wie CharUnicodeInfo.GetUnicodeCategory. Weitere Informationen finden Sie in den Anmerkungen zu Char.GetUnicodeCategory.
Konvertieren einer Rune
in UTF-8 oder UTF-16
Da es sich bei einem Rune
Unicode-Skalarwert um einen Unicode-Skalarwert handelt, kann er in UTF-8-, UTF-16- oder UTF-32-Codierung konvertiert werden. Der Rune
Typ verfügt über integrierte Unterstützung für die Konvertierung in UTF-8 und UTF-16.
Die Rune.EncodeToUtf16 Instanz wird in char
Instanzen konvertiertRune
. Verwenden Sie die Rune.Utf16SequenceLength Eigenschaft, um die Anzahl der char
Instanzen abzufragen, die sich aus der Konvertierung einer Rune
Instanz in UTF-16 ergeben würden. Für die UTF-8-Konvertierung sind ähnliche Methoden vorhanden.
Im folgenden Beispiel wird eine Rune
Instanz in ein char
Array konvertiert. Der Code geht davon aus, dass Sie eine Rune
Instanz in der rune
Variablen haben:
char[] chars = new char[rune.Utf16SequenceLength];
int numCharsWritten = rune.EncodeToUtf16(chars);
Da eine string
Sequenz von UTF-16-Zeichen ist, konvertiert das folgende Beispiel auch eine Rune
Instanz in UTF-16:
string theString = rune.ToString();
Im folgenden Beispiel wird eine Rune
Instanz in ein UTF-8
Bytearray konvertiert:
byte[] bytes = new byte[rune.Utf8SequenceLength];
int numBytesWritten = rune.EncodeToUtf8(bytes);
Die Rune.EncodeToUtf16 Methoden geben Rune.EncodeToUtf8 die tatsächliche Anzahl geschriebener Elemente zurück. Sie lösen eine Ausnahme aus, wenn der Zielpuffer zu kurz ist, um das Ergebnis zu enthalten. Es gibt auch nicht auslösende TryEncodeToUtf8 Methoden und TryEncodeToUtf16 Methoden für Aufrufer, die Ausnahmen vermeiden möchten.
Rune in .NET vs. anderen Sprachen
Der Begriff "Rune" ist im Unicode-Standard nicht definiert. Der Begriff stammt aus der Erstellung von UTF-8. Rob Pike und Ken Thompson suchten nach einem Begriff, um zu beschreiben, was schließlich als Codepunkt bekannt werden würde. Sie beglichen den Begriff "Rune", und Rob Pikes späterer Einfluss auf die Go-Programmiersprache half, den Begriff zu popularisieren.
Der .NET-Typ Rune
entspricht jedoch nicht dem Go-Typ rune
. In Go ist der rune
Typ ein Alias für int32
. Ein Go-Rune ist für einen Unicode-Codepunkt vorgesehen, kann jedoch ein beliebiger 32-Bit-Wert sein, einschließlich ersatzweiser Codepunkte und Werte, die keine rechtlichen Unicode-Codepunkte sind.
Ähnliche Typen in anderen Programmiersprachen finden Sie unter Rusts Grundtyp char
oder Swifts Unicode.Scalar
Typ, die beide Unicode-Skalarwerte darstellen. Sie bieten Funktionen ähnlich wie . Nets Rune
Typ und sie verbieten die Instanziierung von Werten, die keine zulässigen Unicode-Skalarwerte sind.