Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Opmerking
In dit artikel vindt u aanvullende opmerkingen in de referentiedocumentatie voor deze API.
Een Rune exemplaar vertegenwoordigt een Unicode-scalaire waarde, wat betekent dat elk codepunt exclusief het surrogaatbereik (U+D800.) is. U+DFFF). De constructors en conversieoperators van het type valideren de invoer, zodat consumenten de API's kunnen aanroepen, ervan uitgaande dat het onderliggende Rune exemplaar goed is gevormd.
Als u niet bekend bent met de termen Unicode scalaire waarde, codepunt, surrogaatbereik en goed gevormd, raadpleegt u Inleiding tot tekencodering in .NET.
Wanneer gebruikt u het Rune-type
Overweeg het Rune type te gebruiken als uw code:
- Roept API's aan waarvoor Unicode-scalaire waarden zijn vereist
- Surrogaatparen expliciet verwerken
API's waarvoor Unicode-scalaire waarden zijn vereist
Als uw code door de char exemplaren in een string of een ReadOnlySpan<char> loopt, zullen sommige char-methoden niet correct werken op char-exemplaren die zich in het surrogaatbereik bevinden. Voor de volgende API's is bijvoorbeeld een scalaire waarde char vereist om correct te werken:
- Char.GetNumericValue
- Char.GetUnicodeCategory
- Char.IsDigit
- Char.IsLetter
- Char.IsLetterOrDigit
- Char.IsLower
- Char.IsNumber
- Char.IsPunctuation
- Char.IsSymbol
- Char.IsUpper
In het volgende voorbeeld ziet u code die niet goed werkt als een van de char exemplaren surrogaatcodepunten zijn:
// 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 volgt een equivalente code die werkt met een 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;
}
De voorgaande code werkt correct met sommige talen, zoals Engels:
CountLettersInString("Hello")
// Returns 5
Maar het werkt niet goed voor talen buiten het meertalige basisvlak, zoals Osage:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 0
De reden waarom deze methode onjuiste resultaten voor Osage-tekst retourneert, is dat de char exemplaren voor Osage-letters surrogaatcodepunten zijn. Geen enkel surrogaatcodepunt bevat voldoende informatie om te bepalen of het een letter is.
Als u deze code wijzigt om Rune in plaats van char te gebruiken, werkt de methode correct met codepunten buiten de Basis Multilinguale Vlak:
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 volgt een equivalente code die werkt met een ReadOnlySpan<char>:
static int CountLetters(ReadOnlySpan<char> span)
{
int letterCount = 0;
foreach (Rune rune in span.EnumerateRunes())
{
if (Rune.IsLetter(rune))
{ letterCount++; }
}
return letterCount;
}
Met de voorgaande code worden Osage-letters correct geteld:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 8
Code dat expliciet surrogaatparen verwerkt
Overweeg het Rune type te gebruiken als uw code API's aanroept die expliciet werken op surrogaatcodepunten, zoals de volgende methoden:
- Char.IsSurrogate
- Char.IsSurrogatePair
- Char.IsHighSurrogate
- Char.IsLowSurrogate
- Char.ConvertFromUtf32
- Char.ConvertToUtf32
De volgende methode heeft bijvoorbeeld speciale logica voor het verwerken van surrogaatparen 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.");
}
}
}
Dergelijke code is eenvoudiger als deze wordt gebruikt Rune, zoals in het volgende voorbeeld:
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
}
}
Wanneer niet te gebruiken Rune
U hoeft het Rune type niet te gebruiken als uw code:
- Zoekt naar exacte
charovereenkomsten - Splitst een tekenreeks op een bekende karakterwaarde
Als u het Rune type gebruikt, worden mogelijk onjuiste resultaten geretourneerd als uw code:
- Telt het aantal weergavetekens in een
string
Zoeken naar exacte char overeenkomsten
De volgende code doorloopt een string zoekfunctie naar specifieke tekens, waardoor de index van de eerste overeenkomst wordt geretourneerd. U hoeft deze code niet te wijzigen om deze te gebruiken Rune, omdat de code zoekt naar tekens die worden vertegenwoordigd door één 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
}
Een string splitsen op een bekend char
Het is gebruikelijk om string.Split aan te roepen en scheidingstekens zoals ' ' (spatie) of ',' (komma) te gebruiken, zoals in het volgende voorbeeld:
string inputString = "🐂, 🐄, 🐆";
string[] splitOnSpace = inputString.Split(' ');
string[] splitOnComma = inputString.Split(',');
U hoeft hier niet te gebruiken Rune , omdat de code op zoek is naar tekens die worden vertegenwoordigd door één char.
Tellen het aantal weergavetekens in een string
Het aantal Rune exemplaren in een tekenreeks komt mogelijk niet overeen met het aantal door de gebruiker gedetecteerde tekens dat wordt weergegeven bij het weergeven van de tekenreeks.
Omdat Rune exemplaren Unicode-scalaire waarden vertegenwoordigen, kunnen onderdelen die voldoen aan de Unicode-tekstsegmentatierichtlijnen, Rune gebruiken als bouwsteen voor het tellen van weergavetekens.
Het StringInfo type kan worden gebruikt om weergavetekens te tellen, maar het wordt niet correct geteld in alle scenario's voor .NET-implementaties anders dan .NET 5+.
Zie Grapheme-clusters voor meer informatie.
Hoe een Rune te instantiëren
Er zijn verschillende manieren om een Rune exemplaar te verkrijgen. U kunt een constructor gebruiken om een Rune direct te maken vanuit:
Een codepunt.
Rune a = new Rune(0x0061); // LATIN SMALL LETTER A Rune b = new Rune(0x10421); // DESERET CAPITAL LETTER ERcharEén.Rune c = new Rune('a');Een surrogaatpaar
char.Rune d = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
Alle constructors gooien een ArgumentException als de invoer geen geldige Unicode-scalaire waarde vertegenwoordigt.
Er zijn Rune.TryCreate methoden beschikbaar voor aanroepers die geen uitzonderingen willen laten opwerpen bij een fout.
Rune exemplaren kunnen ook worden gelezen uit bestaande invoerreeksen. Op basis van een ReadOnlySpan<char> waarde die UTF-16-gegevens vertegenwoordigt, retourneert de Rune.DecodeFromUtf16 methode bijvoorbeeld het eerste Rune exemplaar aan het begin van het invoerbereik. De Rune.DecodeFromUtf8 methode werkt op dezelfde manier, waarbij een ReadOnlySpan<byte> parameter wordt geaccepteerd die UTF-8-gegevens vertegenwoordigt. Er zijn equivalente methoden om te lezen vanaf het einde van de periode in plaats van het begin van de periode.
Query-eigenschappen van een Rune
Gebruik de Rune eigenschap om de integercodepuntwaarde van een Rune.Value exemplaar op te halen.
Rune rune = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
int codePoint = rune.Value; // = 128302 decimal (= 0x1F52E)
Veel van de statische API's die beschikbaar zijn voor het char type, zijn ook beschikbaar voor het Rune type.
Rune.IsWhiteSpace en Rune.GetUnicodeCategory zijn bijvoorbeeld equivalenten aan Char.IsWhiteSpace en Char.GetUnicodeCategory methoden. De Rune methoden verwerken surrogaatparen correct.
De volgende voorbeeldcode neemt een ReadOnlySpan<char> als invoer en verwijdert van zowel het begin als het einde van de reeks elk Rune dat geen letter of cijfer is.
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;
}
Er zijn enkele API-verschillen tussen char en Rune. Voorbeeld:
- Er is geen
Runeequivalent aan Char.IsSurrogate(Char), omdatRuneexemplaren per definitie nooit surrogaatcodepunten kunnen zijn. - De Rune.GetUnicodeCategory functie retourneert niet altijd hetzelfde resultaat als Char.GetUnicodeCategory. Het retourneert dezelfde waarde als CharUnicodeInfo.GetUnicodeCategory. Zie de opmerkingen over Char.GetUnicodeCategory.
Een Rune converteren naar UTF-8 of UTF-16
Omdat een Rune Unicode-scalaire waarde is, kan deze worden geconverteerd naar UTF-8, UTF-16 of UTF-32-codering. Het Rune type heeft ingebouwde ondersteuning voor conversie naar UTF-8 en UTF-16.
Rune.EncodeToUtf16 converteert een Rune naar char exemplaren. Gebruik de eigenschap char om het aantal Rune exemplaren te achterhalen dat zou ontstaan bij het converteren van een Rune.Utf16SequenceLength exemplaar naar UTF-16. Er bestaan vergelijkbare methoden voor UTF-8-conversie.
In het volgende voorbeeld wordt een Rune object geconverteerd naar een char reeks. In de code wordt ervan uitgegaan dat u een Rune exemplaar in de rune variabele hebt:
char[] chars = new char[rune.Utf16SequenceLength];
int numCharsWritten = rune.EncodeToUtf16(chars);
Omdat een string reeks UTF-16 tekens is, converteert het volgende voorbeeld ook een Rune exemplaar naar UTF-16:
string theString = rune.ToString();
In het volgende voorbeeld wordt een Rune exemplaar geconverteerd naar een UTF-8 bytematrix:
byte[] bytes = new byte[rune.Utf8SequenceLength];
int numBytesWritten = rune.EncodeToUtf8(bytes);
De Rune.EncodeToUtf16 en Rune.EncodeToUtf8 methoden retourneren het werkelijke aantal geschreven elementen. Ze genereren een uitzondering als de doelbuffer te kort is om het resultaat te bevatten. Er zijn ook niet-gooiende TryEncodeToUtf8- en TryEncodeToUtf16-methoden voor bellers die uitzonderingen willen vermijden.
Rune in .NET versus andere talen
De term 'rune' is niet gedefinieerd in de Unicode-standaard. De term dateert van het maken van UTF-8. Rob Pike en Ken Thompson zochten een term om te beschrijven wat uiteindelijk bekend zou worden als een codepunt. Ze kwamen neer op de term 'rune', en Rob Pike's latere invloed op de programmeertaal Go hielp de term populair te maken.
Het .NET-type Rune is echter niet het equivalent van het Go-type rune . In Go is het rune type een alias voor int32. Een Go-rune is bedoeld om een Unicode-codepunt te vertegenwoordigen, maar dit kan elke 32-bits waarde zijn, inclusief surrogaatcodepunten en -waarden die geen legale Unicode-codepunten zijn.
Zie voor vergelijkbare typen in andere programmeertalen het primitieve char type van Rust of het type swiftUnicode.Scalar, die beide Unicode scalaire waarden vertegenwoordigen. Ze bieden functionaliteit die vergelijkbaar is met het type Rune van .NET, en ze staan geen instantiëring toe van waarden die geen geldige Unicode-scalaire waarden zijn.