Struktur System.Text.Rune
Artikel ini menyediakan keterangan tambahan untuk dokumentasi referensi untuk API ini.
Rune Instans mewakili nilai skalar Unicode, yang berarti setiap titik kode tidak termasuk rentang pengganti (U+D800.. U+DFFF). Konstruktor dan operator konversi jenis memvalidasi input, sehingga konsumen dapat memanggil API dengan asumsi bahwa instans yang mendasar Rune terbentuk dengan baik.
Jika Anda tidak terbiasa dengan istilah nilai skalar Unicode, titik kode, rentang pengganti, dan terbentuk dengan baik, lihat Pengenalan pengodean karakter di .NET.
Kapan menggunakan jenis Rune
Pertimbangkan untuk Rune
menggunakan jenis jika kode Anda:
- Memanggil API yang memerlukan nilai skalar Unicode
- Menangani pasangan pengganti secara eksplisit
API yang memerlukan nilai skalar Unicode
Jika kode Anda berulang melalui char
instans dalam atau string
ReadOnlySpan<char>
, beberapa char
metode tidak akan berfungsi dengan benar pada char
instans yang berada dalam rentang pengganti. Misalnya, API berikut memerlukan nilai char
skalar untuk bekerja dengan benar:
- Char.GetNumericValue
- Char.GetUnicodeCategory
- Char.IsDigit
- Char.IsLetter
- Char.IsLetterOrDigit
- Char.IsLower
- Char.IsNumber
- Char.IsPunctuation
- Char.IsSymbol
- Char.IsUpper
Contoh berikut menunjukkan kode yang tidak akan berfungsi dengan benar jika salah char
satu instans adalah titik kode pengganti:
// 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
Berikut kode yang setara yang berfungsi dengan 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;
}
Kode sebelumnya berfungsi dengan benar dengan beberapa bahasa seperti bahasa Inggris:
CountLettersInString("Hello")
// Returns 5
Tetapi tidak akan berfungsi dengan benar untuk bahasa di luar Basic Multilingual Plane, seperti Osage:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 0
Alasan metode ini mengembalikan hasil yang salah untuk teks Osage adalah bahwa char
instans untuk huruf Osage adalah titik kode pengganti. Tidak ada satu titik kode pengganti yang memiliki informasi yang cukup untuk menentukan apakah itu huruf.
Jika Anda mengubah kode ini untuk digunakan Rune
alih-alih char
, metode ini berfungsi dengan benar dengan titik kode di luar Bidang Multibahasa Dasar:
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
Berikut kode yang setara yang berfungsi dengan ReadOnlySpan<char>
:
static int CountLetters(ReadOnlySpan<char> span)
{
int letterCount = 0;
foreach (Rune rune in span.EnumerateRunes())
{
if (Rune.IsLetter(rune))
{ letterCount++; }
}
return letterCount;
}
Kode sebelumnya menghitung huruf Osage dengan benar:
CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 8
Kode yang secara eksplisit menangani pasangan pengganti
Pertimbangkan untuk Rune
menggunakan jenis jika kode Anda memanggil API yang secara eksplisit beroperasi pada titik kode pengganti, seperti metode berikut:
- Char.IsSurrogate
- Char.IsSurrogatePair
- Char.IsHighSurrogate
- Char.IsLowSurrogate
- Char.ConvertFromUtf32
- Char.ConvertToUtf32
Misalnya, metode berikut memiliki logika khusus untuk menangani pasangan pengganti 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.");
}
}
}
Kode tersebut lebih sederhana jika menggunakan Rune
, seperti dalam contoh berikut:
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
}
}
Kapan tidak seharusnya menggunakan Rune
Anda tidak perlu menggunakan Rune
jenis jika kode Anda:
- Mencari kecocokan yang tepat
char
- Memisahkan string pada nilai karakter yang diketahui
Menggunakan jenis dapat Rune
mengembalikan hasil yang salah jika kode Anda:
- Menghitung jumlah karakter tampilan dalam
string
Cari kecocokan yang tepat char
Kode berikut berulang melalui string
mencari karakter tertentu, mengembalikan indeks kecocokan pertama. Tidak perlu mengubah kode ini untuk menggunakan Rune
, karena kode mencari karakter yang diwakili oleh satu 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
}
Memisahkan string pada yang diketahui char
Umum untuk memanggil string.Split
dan menggunakan pemisah seperti ' '
(spasi) atau ','
(koma), seperti dalam contoh berikut:
string inputString = "🐂, 🐄, 🐆";
string[] splitOnSpace = inputString.Split(' ');
string[] splitOnComma = inputString.Split(',');
Tidak perlu digunakan Rune
di sini, karena kode mencari karakter yang diwakili oleh satu char
.
Menghitung jumlah karakter tampilan dalam string
Jumlah Rune
instans dalam string mungkin tidak cocok dengan jumlah karakter yang dapat dirasakan pengguna yang ditampilkan saat menampilkan string.
Karena Rune
instans mewakili nilai skalar Unicode, komponen yang mengikuti panduan segmentasi teks Unicode dapat digunakan Rune
sebagai blok penyusun untuk menghitung karakter tampilan.
StringInfo Jenis dapat digunakan untuk menghitung karakter tampilan, tetapi tidak dihitung dengan benar dalam semua skenario untuk implementasi .NET selain .NET 5+.
Untuk informasi selengkapnya, lihat kluster Grapheme.
Cara membuat instans Rune
Ada beberapa cara untuk mendapatkan Rune
instans. Anda dapat menggunakan konstruktor untuk membuat Rune
langsung dari:
Titik kode.
Rune a = new Rune(0x0061); // LATIN SMALL LETTER A Rune b = new Rune(0x10421); // DESERET CAPITAL LETTER ER
Satu
char
.Rune c = new Rune('a');
Pasangan pengganti
char
.Rune d = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
Semua konstruktor melempar ArgumentException
jika input tidak mewakili nilai skalar Unicode yang valid.
Ada metode yang Rune.TryCreate tersedia untuk penelepon yang tidak ingin pengecualian dilemparkan pada kegagalan.
Rune
instans juga dapat dibaca dari urutan input yang ada. Misalnya, mengingat ReadOnlySpan<char>
yang mewakili data UTF-16, Rune.DecodeFromUtf16 metode mengembalikan instans pertama Rune
di awal rentang input. Metode ini Rune.DecodeFromUtf8 beroperasi sama, menerima ReadOnlySpan<byte>
parameter yang mewakili data UTF-8. Ada metode yang setara untuk dibaca dari akhir rentang alih-alih awal rentang.
Properti kueri dari Rune
Untuk mendapatkan nilai titik kode bilangan Rune
bulat instans, gunakan Rune.Value properti .
Rune rune = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
int codePoint = rune.Value; // = 128302 decimal (= 0x1F52E)
Banyak API statis yang tersedia pada char
jenisnya juga tersedia pada jenisnya Rune
. Misalnya, Rune.IsWhiteSpace dan Rune.GetUnicodeCategory setara dengan Char.IsWhiteSpace metode dan Char.GetUnicodeCategory . Metode Rune
menangani pasangan pengganti dengan benar.
Contoh kode berikut mengambil ReadOnlySpan<char>
sebagai input dan memangkas dari awal dan akhir rentang setiap Rune
yang bukan huruf atau digit.
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;
}
Ada beberapa perbedaan API antara char
dan Rune
. Misalnya:
- Tidak ada
Rune
yang setara Char.IsSurrogate(Char)dengan , karenaRune
instans menurut definisi tidak pernah dapat menjadi titik kode pengganti. - Rune.GetUnicodeCategory tidak selalu mengembalikan hasil yang sama dengan Char.GetUnicodeCategory. Ini mengembalikan nilai yang sama dengan CharUnicodeInfo.GetUnicodeCategory. Untuk informasi selengkapnya, lihat Keterangan di Char.GetUnicodeCategory.
Rune
Mengonversi ke UTF-8 atau UTF-16
Karena merupakan Rune
nilai skalar Unicode, nilai tersebut dapat dikonversi ke pengodean UTF-8, UTF-16, atau UTF-32. Jenis ini Rune
memiliki dukungan bawaan untuk konversi ke UTF-8 dan UTF-16.
Mengonversi Rune.EncodeToUtf16 instans Rune
menjadi char
instans. Untuk mengkueri jumlah char
instans yang akan dihasilkan dari mengonversi Rune
instans ke UTF-16, gunakan Rune.Utf16SequenceLength properti . Metode serupa ada untuk konversi UTF-8.
Contoh berikut mengonversi instans Rune
menjadi char
array. Kode mengasumsikan Anda memiliki Rune
instans dalam rune
variabel:
char[] chars = new char[rune.Utf16SequenceLength];
int numCharsWritten = rune.EncodeToUtf16(chars);
Karena merupakan string
urutan karakter UTF-16, contoh berikut juga mengonversi instans Rune
ke UTF-16:
string theString = rune.ToString();
Contoh berikut mengonversi instans Rune
menjadi UTF-8
array byte:
byte[] bytes = new byte[rune.Utf8SequenceLength];
int numBytesWritten = rune.EncodeToUtf8(bytes);
Metode Rune.EncodeToUtf16 dan Rune.EncodeToUtf8 mengembalikan jumlah elemen aktual yang ditulis. Mereka melemparkan pengecualian jika buffer tujuan terlalu pendek untuk berisi hasilnya. Ada non-pelemparan TryEncodeToUtf8 dan TryEncodeToUtf16 metode juga untuk penelepon yang ingin menghindari pengecualian.
Rune di .NET vs. bahasa lain
Istilah "rune" tidak didefinisikan dalam Standar Unicode. Istilah ini kembali ke pembuatan UTF-8. Rob Pike dan Ken Thompson sedang mencari istilah untuk menggambarkan apa yang akhirnya akan dikenal sebagai titik kode. Mereka menetap pada istilah "rune", dan pengaruh Rob Pike kemudian atas bahasa pemrograman Go membantu memprogram istilah tersebut.
Namun, jenis .NET Rune
bukan setara dengan jenis Go rune
. Di Go, jenisnya rune
adalah alias untuk int32
. Rune Go dimaksudkan untuk mewakili titik kode Unicode, tetapi dapat berupa nilai 32-bit apa pun, termasuk titik kode pengganti dan nilai yang bukan poin kode Unicode legal.
Untuk jenis serupa dalam bahasa pemrograman lainnya, lihat Jenis primitif char
Rust atau jenis SwiftUnicode.Scalar
, yang keduanya mewakili nilai skalar Unicode. Mereka menyediakan fungsionalitas yang mirip dengan . Rune
Jenis NET, dan melarang instansiasi nilai yang bukan nilai skalar Unicode legal.
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk