Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.
Rune Wystąpienie reprezentuje wartość skalarną Unicode, co oznacza dowolny punkt kodu z wyłączeniem zakresu zastępczego (U+D800..U+DFFF). Konstruktory i operatory konwersji typu weryfikują dane wejściowe, aby użytkownicy mogli wywoływać interfejsy API przy założeniu, że obiekt bazowy Rune jest poprawnie utworzony.
Jeśli nie znasz terminów wartość skalarna Unicode, punkt kodu, zakres zastępczy i poprawnie sformułowany, zobacz Wprowadzenie do kodowania znaków na platformie .NET.
Kiedy używać typu Rune
Rozważ użycie typu Rune, jeśli Twój kod:
- Wywołuje API, które wymagają wartości skalarnych Unicode
- Jawnie obsługuje pary zastępcze
Interfejsy programowania aplikacji (API) wymagające wartości skalarnych Unicode
Jeśli twój kod wykonuje iterację po wystąpieniach char w obiekcie string lub ReadOnlySpan<char>, niektóre metody char nie będą działać poprawnie na wystąpieniach char, które znajdują się w zakresie zastępczym. Na przykład, aby działały poprawnie, następujące interfejsy API wymagają wartości skalarnej char.
- Char.GetNumericValue
- Char.GetUnicodeCategory
- Char.IsDigit
- Char.IsLetter
- Char.IsLetterOrDigit
- Char.IsLower
- Char.IsNumber
- Char.IsPunctuation
- Char.IsSymbol
- Char.IsUpper
W poniższym przykładzie pokazano kod, który nie będzie działał poprawnie, jeśli którykolwiek z char wystąpień jest zastępczymi punktami kodu:
// 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
Oto równoważny kod, który działa z elementem 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;
}
Powyższy kod działa poprawnie w niektórych językach, takich jak angielski:
CountLettersInString("Hello")
// Returns 5
Jednak nie będzie działać poprawnie w przypadku języków spoza podstawowej płaszczyzny wielojęzycznej, takiej jak Osage:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 0
Powodem, dla którego ta metoda zwraca nieprawidłowe wyniki dla tekstu Osage, jest to, że wystąpienia liter Osage są punktami kodu zastępczymi. Żaden pojedynczy punkt kodu zastępczego nie ma wystarczającej ilości informacji, aby ustalić, czy jest to litera.
Jeśli zmienisz ten kod, aby używał Rune zamiast char, metoda działa poprawnie z punktami kodu poza podstawową płaszczyzną wielojęzyczną:
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
Oto równoważny kod, który działa z elementem ReadOnlySpan<char>:
static int CountLetters(ReadOnlySpan<char> span)
{
int letterCount = 0;
foreach (Rune rune in span.EnumerateRunes())
{
if (Rune.IsLetter(rune))
{ letterCount++; }
}
return letterCount;
}
Powyższy kod poprawnie zlicza litery Osage:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 8
Kod, który jawnie obsługuje pary zastępcze
Rozważ użycie typu Rune, jeśli kod wywołuje interfejsy API, które jawnie działają na punktach kodowych zastępczych, takich jak następujące metody.
- Char.IsSurrogate
- Char.IsSurrogatePair
- Char.IsHighSurrogate
- Char.IsLowSurrogate
- Char.ConvertFromUtf32
- Char.ConvertToUtf32
Na przykład następująca metoda ma specjalną logikę do obsługi par zastępczych 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.");
}
}
}
Taki kod jest prostszy, jeśli używa Rune, jak w poniższym przykładzie:
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
}
}
Kiedy nie należy używać Rune
Nie musisz używać Rune typu, jeśli kod:
- Szuka dokładnych
chardopasowań - Dzieli ciąg na znanej wartości char
Użycie typu Rune może zwracać nieprawidłowe wyniki, jeśli twój kod:
- Zlicza liczbę znaków wyświetlanych w elemencie
string
Szukaj dokładnych dopasowań char
Kod przechodzi przez string, szukając określonych znaków, zwracając indeks pierwszego dopasowania. Nie trzeba zmieniać tego kodu, aby używał Rune, ponieważ kod szuka znaków reprezentowanych przez pojedynczy 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
}
Podziel ciąg znaków na podstawie znanego char
Często należy uruchomić string.Split i używać separatorów, takich jak ' ' (spacja) lub ',' (przecinek), jak w poniższym przykładzie:
string inputString = "🐂, 🐄, 🐆";
string[] splitOnSpace = inputString.Split(' ');
string[] splitOnComma = inputString.Split(',');
Nie ma tutaj potrzeby użycia Rune , ponieważ kod szuka znaków reprezentowanych przez pojedynczy charelement .
Policz liczbę znaków wyświetlanych w string
Liczba Rune wystąpień w ciągu może być niezgodna z liczbą znaków, które można zobaczyć podczas wyświetlania ciągu.
Ponieważ Rune wystąpienia reprezentują wartości skalarne Unicode, składniki zgodne z wytycznymi dotyczącymi segmentacji tekstu Unicode mogą używać Rune jako bloku konstrukcyjnego do zliczania znaków wyświetlania.
Typ StringInfo może służyć do zliczania znaków wyświetlania, ale nie jest poprawnie liczony we wszystkich scenariuszach dla implementacji .NET innych niż .NET 5+.
Aby uzyskać więcej informacji, zobacz Grapheme clusters (Klastry Grapheme).
Jak utworzyć wystąpienie obiektu Rune
Są różne sposoby, aby uzyskać instancję Rune. Konstruktora można użyć do utworzenia obiektu Rune bezpośrednio z:
Punkt kodowy.
Rune a = new Rune(0x0061); // LATIN SMALL LETTER A Rune b = new Rune(0x10421); // DESERET CAPITAL LETTER ERcharPojedynczy element .Rune c = new Rune('a');Para zastępcza
char.Rune d = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
Wszystkie konstruktory zgłaszają wartość ArgumentException , jeśli dane wejściowe nie reprezentują prawidłowej wartości skalarnej Unicode.
Rune.TryCreate Istnieją metody dostępne dla osób wywołujących, którzy nie chcą zgłaszać wyjątków w przypadku awarii.
Rune wystąpienia mogą być również odczytywane z istniejących sekwencji wejściowych. Na przykład, jeśli chodzi o ReadOnlySpan<char>, który reprezentuje dane w UTF-16, metoda Rune.DecodeFromUtf16 zwraca pierwsze Rune wystąpienie na początku prostokąta danych wejściowych. Metoda Rune.DecodeFromUtf8 działa podobnie, akceptując ReadOnlySpan<byte> parametr reprezentujący dane UTF-8. Istnieją równoważne metody odczytywania od końca zakresu zamiast początku zakresu.
Właściwości kwerendy obiektu Rune
Aby uzyskać wartość liczby całkowitej punktu kodu instancji Rune, użyj właściwości Rune.Value.
Rune rune = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
int codePoint = rune.Value; // = 128302 decimal (= 0x1F52E)
Wiele statycznych interfejsów API dostępnych w typie char jest również dostępnych w typie Rune . Na przykład Rune.IsWhiteSpace i Rune.GetUnicodeCategory są równoważne metodom Char.IsWhiteSpace i Char.GetUnicodeCategory. Metody Rune poprawnie obsługują pary zastępcze.
Poniższy przykładowy kod przyjmuje ReadOnlySpan<char> jako dane wejściowe i przycina zarówno z początku, jak i z końca ciągu każdy Rune, który nie jest literą ani cyfrą.
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;
}
Istnieją pewne różnice między char a Rune w zakresie API. Przykład:
- Nie ma
Runeodpowiednika Char.IsSurrogate(Char)elementu, ponieważ zgodnie z definicją wystąpieniaRunenigdy nie mogą być punktami kodowania zastępczego. - Funkcja Rune.GetUnicodeCategory nie zawsze zwraca ten sam wynik co Char.GetUnicodeCategory. Zwraca tę samą wartość co CharUnicodeInfo.GetUnicodeCategory. Aby uzyskać więcej informacji, zobacz uwagi na temat Char.GetUnicodeCategory.
Konwertuj Rune na UTF-8 lub UTF-16
Rune Ponieważ element jest wartością skalarną Unicode, można go przekonwertować na kodowanie UTF-8, UTF-16 lub UTF-32. Typ Rune ma wbudowaną obsługę konwersji na utF-8 i UTF-16.
Element Rune.EncodeToUtf16 konwertuje wystąpienie Rune na wystąpienia char. Aby sprawdzić liczbę char wystąpień, które wynikają z konwersji Rune wystąpienia na UTF-16, skorzystaj z właściwości Rune.Utf16SequenceLength. Podobne metody istnieją dla konwersji UTF-8.
Poniższy przykład konwertuje wystąpienie Rune na tablicę char. W kodzie przyjęto założenie, że masz wystąpienie Rune w zmiennej rune.
char[] chars = new char[rune.Utf16SequenceLength];
int numCharsWritten = rune.EncodeToUtf16(chars);
Ponieważ string jest sekwencją znaków UTF-16, poniższy przykład konwertuje wystąpienie Rune na UTF-16.
string theString = rune.ToString();
Poniższy przykład konwertuje wystąpienie Rune na tablicę bajtów UTF-8.
byte[] bytes = new byte[rune.Utf8SequenceLength];
int numBytesWritten = rune.EncodeToUtf8(bytes);
Metody Rune.EncodeToUtf16 i Rune.EncodeToUtf8 zwracają rzeczywistą liczbę zapisanych elementów. Zgłaszają wyjątek, jeśli bufor docelowy jest zbyt krótki, aby zawierać wynik. Istnieją również metody TryEncodeToUtf8 i TryEncodeToUtf16 , które nie powodują zgłaszania wyjątków, dla wywołujących chcących ich uniknąć.
"Rune w .NET w porównaniu z innymi językami"
Termin "rune" nie jest zdefiniowany w Standardzie Unicode. Termin sięga powstania UTF-8. Rob Pike i Ken Thompson szukali terminu, aby opisać, co ostatecznie stanie się znane jako punkt kodu. Zdecydowali się na termin "rune", a później wpływ Roba Pike'a na język Go pomógł spopularyzować ten termin.
Jednak typ platformy .NET Rune nie jest odpowiednikiem typu Go rune . W języku rune Go typ jest aliasem dla int32. Runa w języku Go powinna reprezentować punkt kodowy Unicode, ale może to być dowolna 32-bitowa wartość, w tym zastępcze punkty kodowe i wartości, które nie są prawidłowymi punktami kodowymi Unicode.
Aby zapoznać się z podobnymi typami w innych językach programowania, zobacz Typ pierwotny char Rust lub typ swiftUnicode.Scalar, z których oba reprezentują wartości skalarne Unicode. Zapewniają one funkcjonalność podobną do typu Rune z platformy .NET i nie zezwalają na tworzenie instancji wartości, które nie są prawidłowymi wartościami skalarnymi Unicode.