System.Text.Rune 構造体
この記事では、この API のリファレンス ドキュメントへの補足的な解説を提供します。
インスタンスは Rune Unicode スカラー値を表します。これは、サロゲート範囲 (U+D800.) を除く任意のコード ポイントを意味します。U+DFFF)。 型のコンストラクターと変換演算子は入力を検証するため、コンシューマーは基になる Rune インスタンスが整形式であると仮定して API を呼び出すことができます。
Unicode スカラー値、コード ポイント、サロゲート範囲、整形式の用語に慣れていない場合は、「.NET での文字エンコードの概要」を参照してください。
Rune 型を使用する場合
コードが次の場合は、型の Rune
使用を検討してください。
- Unicode スカラー値を必要とする API を呼び出す
- サロゲート ペアを明示的に処理する
Unicode スカラー値を必要とする API
コードが a または a string
ReadOnlySpan<char>
のインスタンスをchar
反復処理する場合、サロゲート範囲内のインスタンスでchar
一部のchar
メソッドが正しく動作しません。 たとえば、次の API では、スカラー値 char
が正しく機能する必要があります。
- Char.GetNumericValue
- Char.GetUnicodeCategory
- Char.IsDigit
- Char.IsLetter
- Char.IsLetterOrDigit
- Char.IsLower
- Char.IsNumber
- Char.IsPunctuation
- Char.IsSymbol
- Char.IsUpper
次の例は、いずれかのインスタンスがサロゲート コード ポイントの場合に 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 文字の char
インスタンスがサロゲート コード ポイントであるためです。 1 つのサロゲート コード ポイントには、文字かどうかを判断するのに十分な情報がありません。
代わりにchar
使用Rune
するようにこのコードを変更した場合、メソッドは Basic 多言語プレーンの外部のコード ポイントで正しく動作します。
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.IsSurrogate
- Char.IsSurrogatePair
- Char.IsHighSurrogate
- Char.IsLowSurrogate
- Char.ConvertFromUtf32
- Char.ConvertToUtf32
たとえば、次のメソッドには、サロゲート 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
一致を検索します - 既知の文字値で文字列を分割します
コードが次の場合、型を Rune
使用すると正しくない結果が返される可能性があります。
- 内の表示文字数をカウントします。
string
完全 char
一致を探す
次のコードは、特定の文字の検索を string
反復処理し、最初の一致のインデックスを返します。 コードが 1 つのchar
文字で表される文字を検索するため、このコードを使用Rune
するように変更する必要はありません。
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(',');
コードは単一char
の文字で表される文字を探しているので、ここで使用Rune
する必要はありません。
内の表示文字数をカウントします。 string
文字列内のインスタンスの Rune
数が、文字列を表示するときに表示されるユーザーが認識できる文字の数と一致しない可能性があります。
インスタンスは Unicode スカラー値を表しているためRune
、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
1つの
char
。Rune c = new Rune('a');
サロゲート
char
ペア。Rune d = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
すべてのコンストラクターは、入力が有効な Unicode スカラー値を表していない場合に an をスロー ArgumentException
します。
失敗した場合に Rune.TryCreate 例外をスローしたくない呼び出し元に使用できるメソッドがあります。
Rune
インスタンスは、既存の入力シーケンスから読み取ることもできます。 たとえば、UTF-16 データを表す a ReadOnlySpan<char>
を指定すると、メソッドは 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.GetUnicodeCategoryChar.GetUnicodeCategory同等Char.IsWhiteSpaceです。 メソッドは Rune
サロゲート ペアを正しく処理します。
次のコード例では、入力として a を 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
. 次に例を示します。
- 定義上のインスタンスをサロゲート コード ポイントにすることはできませんの
Rune
で、これに相当Char.IsSurrogate(Char)するものはありませんRune
。 - と Rune.GetUnicodeCategory 同じ結果 Char.GetUnicodeCategoryが返されるわけではありません。 と同じ値 CharUnicodeInfo.GetUnicodeCategoryが返されます。 詳細については、「解説Char.GetUnicodeCategory」を参照してください。
a Rune
から UTF-8 または UTF-16 への変換
a Rune
は Unicode スカラー値であるため、UTF-8、UTF-16、または UTF-32 エンコードに変換できます。 この Rune
型には、UTF-8 および UTF-16 への変換が組み込まれています。
インスタンス Rune.EncodeToUtf16 を Rune
インスタンスに char
変換します。 インスタンスを UTF-16 に変換した結果として発生するRune
インスタンスのchar
数を照会するには、このプロパティをRune.Utf16SequenceLength使用します。 UTF-8 変換にも同様のメソッドが存在します。
次の例では、インスタンスを Rune
配列に char
変換します。 このコードでは、変数に Rune
インスタンス rune
があることを前提としています。
char[] chars = new char[rune.Utf16SequenceLength];
int numCharsWritten = rune.EncodeToUtf16(chars);
a string
は UTF-16 文字のシーケンスであるため、次の例ではインスタンスも UTF-16 に変換 Rune
します。
string theString = rune.ToString();
次の例では、インスタンスを Rune
バイト配列に UTF-8
変換します。
byte[] bytes = new byte[rune.Utf8SequenceLength];
int numBytesWritten = rune.EncodeToUtf8(bytes);
and Rune.EncodeToUtf8 メソッドはRune.EncodeToUtf16、書き込まれた要素の実際の数を返します。 ターゲット バッファーが短すぎて結果を含められなかった場合は、例外がスローされます。 例外を TryEncodeToUtf8 回避したい呼び出し TryEncodeToUtf16 元には、スローやメソッドはありません。
.NET でのルーンと他の言語
"rune" という用語は、Unicode 標準では定義されていません。 この用語は UTF-8 の作成に遡ります。 Rob Pike と Ken Thompson は、最終的に何がコード ポイントとして知られるかを説明する用語を探していました。 彼らは「ルーン」という用語に落ち着き、後にGoプログラミング言語に対するロブ・パイクの影響が用語の普及に役立ちました。
ただし、.NET Rune
型は Go rune
型と同等ではありません。 Go では、この rune
型は 〗の エイリアス int32
です。 Go ルーンは Unicode コード ポイントを表すことを目的としていますが、サロゲート コード ポイントや有効な Unicode コード ポイントではない値など、任意の 32 ビット値を指定できます。
他のプログラミング言語でも同様の型については、Rust のプリミティブ型または Swift のUnicode.Scalar
型を参照してください。どちらも Unicode スカラー値を表char
します。 これらは、次のような機能を提供します。NET の Rune
型であり、有効な Unicode スカラー値ではない値のインスタンス化を禁止します。
.NET