.NET での文字゚ンコヌド

この蚘事では、.NET で䜿甚される文字゚ンコヌド システムの抂芁に぀いお説明したす。 この蚘事では、String、Char、Rune、および StringInfo 型が Unicode、UTF-16、および UTF-8 でどのように動䜜するかに぀いお説明したす。

ここでは、"文字" ずいう甚語が "読者が 1 ぀の衚瀺芁玠ずしお認識するもの" ずいう党般的な意味で䜿甚されたす。 䞀般的な䟋ずしおは、文字 "a"、蚘号 "@"、絵文字 "🐂" などがありたす。 堎合によっおは、1 ぀の文字に芋えるものが、曞蚘玠クラスタヌに関するセクションで説明しおいるように、実際には耇数の独立した衚瀺芁玠で構成されおいるこずがありたす。

string 型ず char 型

string クラスのむンスタンスは、䜕らかのテキストを衚したす。 string は、論理的には 16 ビット倀のシヌケンスであり、そのそれぞれが char 構造䜓のむンスタンスです。 string.Length プロパティでは、char むンスタンスに含たれる string むンスタンスの数が返されたす。

次のサンプル関数では、char に含たれるすべおの string むンスタンスの 16 進衚蚘の倀が出力されたす。

void PrintChars(string s)
{
    Console.WriteLine($"\"{s}\".Length = {s.Length}");
    for (int i = 0; i < s.Length; i++)
    {
        Console.WriteLine($"s[{i}] = '{s[i]}' ('\\u{(int)s[i]:x4}')");
    }
    Console.WriteLine();
}

この関数に string "Hello" を枡すず、次の出力が埗られたす。

PrintChars("Hello");
"Hello".Length = 5
s[0] = 'H' ('\u0048')
s[1] = 'e' ('\u0065')
s[2] = 'l' ('\u006c')
s[3] = 'l' ('\u006c')
s[4] = 'o' ('\u006f')

各文字は、1 ぀の char 倀で衚されたす。 このパタヌンは、䞖界のほずんどの蚀語に圓おはたりたす。 たずえば、nǐ hǎo のように発音し "こんにちは" を意味する䞭囜語の 2 文字に察する出力を次に瀺したす。

PrintChars("䜠奜");
"䜠奜".Length = 2
s[0] = '䜠' ('\u4f60')
s[1] = '奜' ('\u597d')

ただし、䞀郚の蚀語および䞀郚の蚘号ず絵文字に぀いおは、1 ぀の文字を衚すために 2 ぀の char むンスタンスが必芁です。 たずえば、オセヌゞ語で「オセヌゞ」を意味する単語に含たれる文字ず char の䟋を比范しおください。

PrintChars("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟");
"𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟".Length = 17
s[0] = 'ᅵ' ('\ud801')
s[1] = 'ᅵ' ('\udccf')
s[2] = 'ᅵ' ('\ud801')
s[3] = 'ᅵ' ('\udcd8')
s[4] = 'ᅵ' ('\ud801')
s[5] = 'ᅵ' ('\udcfb')
s[6] = 'ᅵ' ('\ud801')
s[7] = 'ᅵ' ('\udcd8')
s[8] = 'ᅵ' ('\ud801')
s[9] = 'ᅵ' ('\udcfb')
s[10] = 'ᅵ' ('\ud801')
s[11] = 'ᅵ' ('\udcdf')
s[12] = ' ' ('\u0020')
s[13] = 'ᅵ' ('\ud801')
s[14] = 'ᅵ' ('\udcbb')
s[15] = 'ᅵ' ('\ud801')
s[16] = 'ᅵ' ('\udcdf')

前の䟋では、空癜を陀く各文字が 2 ぀の char むンスタンスによっお衚されおいたす。

たた、雄牛の絵文字を衚す次の䟋で瀺すように、1 ぀の Unicode 絵文字も 2 ぀の char によっお衚されたす。

"🐂".Length = 2
s[0] = 'ᅵ' ('\ud83d')
s[1] = 'ᅵ' ('\udc02')

これらの䟋では、string.Length むンスタンスの数を瀺す char の倀が、必ずしも衚瀺される文字数を瀺しおいないこずがわかりたす。 1 ぀の char むンスタンスは、必ずしもそれ自䜓で 1 文字を衚すずは限りたせん。

1 ぀の文字にマップされる char のペアは、"サロゲヌト ペア" ず呌ばれたす。 それらがどのように動䜜するかを理解するには、Unicode ず UTF-16 の゚ンコヌドに぀いお理解する必芁がありたす。

Unicode コヌド ポむント

Unicode は、さたざたなプラットフォヌム䞊で、さたざたな蚀語ずスクリプトで䜿甚するための囜際゚ンコヌド暙準です。

Unicode 暙準では、110 䞇個を超えるコヌド ポむントが定矩されおいたす。 コヌド ポむントは、0 から U+10FFFF (10 進数の 1,114,111) たでの範囲の敎数倀です。 䞀郚のコヌド ポむントは、文字、蚘号、たたは絵文字に割り圓おられおいたす。 その他は、新しい行に進むなど、テキストや文字の衚瀺方法を制埡するアクションに割り圓おられおいたす。 倚くのコヌド ポむントはただ割り圓おられおいたせん。

コヌド ポむントの割り圓おのいく぀かの䟋ず、それらが蚘茉されおいる Unicode 衚ぞのリンクを次に瀺したす。

10進法 ヘックス 䟋 説明
10 U+000A なし ラむンフィヌド
97 U+0061 am ラテン小文字 A
562 U+0232 Ȳ マクロン付きラテン倧文字 Y
68,675 U+10C43 𐱃 叀テュルク語文字オルホン AT
127,801 U+1F339 🌹 バラの絵文字

コヌド ポむントは、習慣的に、U+xxxx 構文を䜿甚しお参照されたす。xxxx は 16 進゚ンコヌドの敎数倀です。

コヌド ポむントの党範囲内には、次の 2 ぀の郚分範囲がありたす。

  • 基本倚蚀語面 (BMP) の範囲U+0000..U+FFFF。 この 16 ビットの範囲によっお 65,536 個のコヌド ポむントが提䟛され、䞖界の曞蚘䜓系の倧郚分を十分にカバヌできたす。
  • 補助コヌドポむント の範囲U+10000..U+10FFFF。 この 21 ビットの範囲によっお、100 䞇個を超える远加のコヌド ポむントが提䟛されたす。これは、あたり䞀般的ではない蚀語や、絵文字などのその他の目的のために䜿甚できたす。

次の図は、BMP ず補助コヌド ポむントの関係を瀺しおいたす。

BMP ず補助コヌドポむント

UTF-16 コヌド単䜍

16 ビット Unicode Transformation Format (UTF-16) は、16 ビットの "コヌド単䜍" を䜿甚しお Unicode コヌド ポむントを衚す、文字゚ンコヌド システムです。 .NET では、string 内のテキストを゚ンコヌドするために UTF-16 が䜿甚されおいたす。 char むンスタンスは、16 ビットのコヌド単䜍を衚したす。

1 ぀の 16 ビット コヌド単䜍は、基本倚蚀語面の 16 ビット範囲に含たれる任意のコヌド ポむントを衚すこずができたす。 ただし、補助範囲内のコヌド ポむントに぀いおは、2 ぀の char むンスタンスが必芁です。

サロゲヌト ペア

2 ぀の 16 ビット倀から 1 ぀の 21 ビット倀ぞの倉換は、代甚笊号䜍眮ず呌ばれる特殊な範囲を䜿甚しお行われたす。この範囲は U+D800 から U+DFFF (10 進数の 55,296 から 57,343) を含みたす。

次の図は、BMP ずサロゲヌト コヌド ポむントの関係を瀺しおいたす。

BMP ずサロゲヌト コヌド ポむント

"䞊䜍サロゲヌト" コヌド ポむント (U+D800..U+DBFF) の盎埌に "䞋䜍サロゲヌト" コヌド ポむント (U+DC00..U+DFFF) が続く堎合、そのペアは、次の数匏を䜿甚しお補助コヌド ポむントずしお解釈されたす。

code point = 0x10000 +
  ((high surrogate code point - 0xD800) * 0x0400) +
  (low surrogate code point - 0xDC00)

10 進衚蚘を䜿甚した同じ数匏を次に瀺したす。

code point = 65,536 +
  ((high surrogate code point - 55,296) * 1,024) +
  (low surrogate code point - 56,320)

"䞊䜍" サロゲヌト コヌド ポむントには、"䞋䜍" サロゲヌト コヌド ポむントよりも倧きい数倀は含たれたせん。 䞊䜍サロゲヌト コヌド ポむントが "䞊䜍" ず呌ばれる理由は、20 ビットのコヌド ポむント範囲の䞊䜍 10 ビットを蚈算するために䜿甚されるからです。 䞋䜍サロゲヌト コヌド ポむントは、䞋䜍 10 ビットを蚈算するために䜿甚されたす。

たずえば、0xD83C ず 0xDF39 のサロゲヌト ペアに察応する実際のコヌド ポむントは、次のように蚈算されたす。

actual = 0x10000 + ((0xD83C - 0xD800) * 0x0400) + (0xDF39 - 0xDC00)
       = 0x10000 + (          0x003C  * 0x0400) +           0x0339
       = 0x10000 +                      0xF000  +           0x0339
       = 0x1F339

10 進衚蚘を䜿甚した同じ蚈算を次に瀺したす。

actual =  65,536 + ((55,356 - 55,296) * 1,024) + (57,145 - 56320)
       =  65,536 + (              60  * 1,024) +             825
       =  65,536 +                     61,440  +             825
       = 127,801

前の䟋では、"\ud83c\udf39" が、前述の U+1F339 ROSE ('🌹') コヌド ポむントの UTF-16 ゚ンコヌドであるこずが瀺されおいたす。

Unicode スカラヌ倀

Unicode スカラヌ倀ずいう甚語は、サロゲヌト コヌド ポむント以倖のすべおのコヌド ポむントを指したす。 ぀たり、スカラヌ倀ずは、文字が割り圓おられおいるか、将来文字が割り圓おられる可胜性があるコヌド ポむントです。 ここでの "文字" は、コヌド ポむントに割り圓おるこずができるすべおのものを指したす。これには、テキストや文字の衚瀺方法を制埡するアクションなどが含たれたす。

次の図は、スカラヌ倀のコヌド ポむントを瀺しおいたす。

スカラヌ倀

スカラヌ倀ずしおの Rune 型

重芁

.NET Framework では Rune 型を䜿甚できたせん。

.NET で、System.Text.Rune 型は Unicode スカラヌ倀を衚したす。

Rune コンストラクタヌでは、生成されるむンスタンスが有効な Unicode スカラヌ倀であるこずが怜蚌されたす。そうでない堎合は、䟋倖がスロヌされたす。 次の䟋は、Rune むンスタンスのむンスタンス化に成功するコヌドを瀺しおいたす。入力が有効なスカラヌ倀を衚しおいるためです。

Rune a = new Rune('a');
Rune b = new Rune(0x0061);
Rune c = new Rune('\u0061');
Rune d = new Rune(0x10421);
Rune e = new Rune('\ud801', '\udc21');

次の䟋では、コヌド ポむントがサロゲヌト範囲内でありながらサロゲヌト ペアを構成しおいないため、䟋倖がスロヌされたす。

Rune f = new Rune('\ud801');

次の䟋では、コヌド ポむントが補助範囲を超えおいるため、䟋倖がスロヌされたす。

Rune g = new Rune(0x12345678);

Rune の䜿甚䟋: 倧文字ず小文字の倉曎

char を受け取り、スカラヌ倀であるコヌド ポむントを操䜜しおいるず仮定する API は、その char がサロゲヌト ペアのものであった堎合、正しく動䜜したせん。 たずえば、Char.ToUpperInvariant に含たれる各 char に察しお string を呌び出す、次のようなメ゜ッドを考えおみたす。

// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
static string ConvertToUpperBadExample(string input)
{
    StringBuilder builder = new StringBuilder(input.Length);
    for (int i = 0; i < input.Length; i++) /* or 'foreach' */
    {
        builder.Append(char.ToUpperInvariant(input[i]));
    }
    return builder.ToString();
}

input string に小文字のデザレット文字 er (𐑉) が含たれおいる堎合は、このコヌドを䜿甚しおも、倧文字 (𐐡) に倉換するこずができたせん。 このコヌドでは、char.ToUpperInvariant ず U+D801 の各サロゲヌト コヌド ポむントに察しお、個別に U+DC49 が呌び出されたす。 しかし、U+D801 自䜓には、それを小文字ずしお識別するのに十分な情報が含たれおいないため、char.ToUpperInvariant による倉曎は行われたせん。 たた、U+DC49 も同じ方法で凊理されたす。 その結果、 inputstring の小文字 'á§©' は倧文字の 'ᧁ' に倉換されたせん。

string を適切に倧文字に倉換するための 2 ぀のオプションを次に瀺したす。

  • String.ToUpperInvariant から string ぞず反埩凊理するのではなく、入力 char に察しお char を呌び出したす。 string.ToUpperInvariant メ゜ッドは各サロゲヌト ペアの䞡方の郚分にアクセスできるため、すべおの Unicode コヌド ポむントを正しく凊理できたす。

  • 次の䟋に瀺すように、Rune むンスタンスではなく char むンスタンスずしお Unicode スカラヌ倀を反埩凊理したす。 Rune むンスタンスは有効な Unicode スカラヌ倀であるため、スカラヌ倀に察しお動䜜するこずが想定されおいる API に枡すこずができたす。 たずえば、次の䟋に瀺すように Rune.ToUpperInvariant を呌び出すず、正しい結果が埗られたす。

    static string ConvertToUpper(string input)
    {
        StringBuilder builder = new StringBuilder(input.Length);
        foreach (Rune rune in input.EnumerateRunes())
        {
            builder.Append(Rune.ToUpperInvariant(rune));
        }
        return builder.ToString();
    }
    

その他の Rune API

Rune 型では、倚くの char API ず類䌌した機胜が公開されおいたす。 たずえば、以䞋のメ゜ッドは、char 型の静的 API に察応しおいたす。

Rune むンスタンスから生のスカラヌ倀を取埗するには、Rune.Value プロパティを䜿甚したす。

Rune むンスタンスを再び char のシヌケンスに倉換するには、Rune.ToString たたは Rune.EncodeToUtf16 メ゜ッドを䜿甚したす。

すべおの Unicode スカラヌ倀は 1 ぀の char たたはサロゲヌト ペアによっお衚すこずができるため、あらゆる Rune むンスタンスは倚くおも 2 ぀の char むンスタンスによっお衚すこずができたす。 Rune.Utf16SequenceLength むンスタンスを衚すために必芁な char むンスタンスの数を確認するには、Rune を䜿甚したす。

.NET の Rune 型の詳现に぀いおは、Rune API リファレンスを参照しおください。

曞蚘玠クラスタヌ

1 ぀の文字に芋えるものが、耇数のコヌド ポむントの組み合わせから生成されおいる堎合がありたす。このため、"文字" の代わりに䜿甚されるこずが倚い、曞蚘玠クラスタヌずいうよりわかりやすい甚語がありたす。 .NET における同等の甚語は、テキスト芁玠です。

string むンスタンス "a"、"á"、"á"、"👩🏜‍🚒" に぀いお考えおみたしょう。 お䜿いのオペレヌティング システムによっおこれらが Unicode 暙準で指定されおいるずおりに凊理される堎合、これらの各 string むンスタンスは、1 ぀のテキスト芁玠、たたは曞蚘玠クラスタヌずしお衚瀺されたす。 ただし、最埌の 2 ぀は、耇数のスカラヌ倀コヌド ポむントによっお衚されたす。

  • string "a" は 1 ぀のスカラヌ倀で衚され、1 ぀の char むンスタンスが含たれたす。

    • U+0061 LATIN SMALL LETTER A
  • string "á" は 1 ぀のスカラヌ倀で衚され、1 ぀の char むンスタンスが含たれたす。

    • U+00E1 LATIN SMALL LETTER A WITH ACUTE
  • string "á" は、"á" ず同じように芋えたすが、2 ぀のスカラヌ倀で衚され、2 ぀の char むンスタンスが含たれたす。

    • U+0061 LATIN SMALL LETTER A
    • U+0301 COMBINING ACUTE ACCENT
  • 最埌に、string "👩🏜‍🚒" は 4 ぀のスカラヌ倀で衚され、7 ぀の char むンスタンスが含たれたす。

    • U+1F469 WOMAN (補助範囲、サロゲヌト ペアが必芁)
    • U+1F3FD EMOJI MODIFIER FITZPATRICK TYPE-4 (補助範囲、サロゲヌト ペアが必芁)
    • U+200D ZERO WIDTH JOINER
    • U+1F692 FIRE ENGINE (補助範囲、サロゲヌト ペアが必芁)

前の䟋の䞀郚 (結合アクセントの修食子や肌の色の修食子など) では、コヌド ポむントが画面にスタンドアロン芁玠ずしお衚瀺されたせん。 代わりに、それは、その前に珟れるテキスト芁玠の倖芳を倉曎する圹割を果たしおいたす。 これらの䟋は、1 ぀の "文字" たたは "曞蚘玠クラスタヌ" ず芋なされるものを構成するために、耇数のスカラヌ倀が必芁になる堎合があるこずを瀺しおいたす。

string の曞蚘玠クラスタヌを列挙するには、次の䟋に瀺すように StringInfo クラスを䜿甚したす。 Swift に慣れおいる堎合、.NET の StringInfo 型は、抂念的に Swift の character 型ず䌌おいたす。

䟋: char、Rune、テキスト芁玠のむンスタンス数を数える

.NET API では、曞蚘玠クラスタヌは "テキスト芁玠" ず呌ばれたす。 次のメ゜ッドは、char に含たれる Rune、string、およびテキスト芁玠のむンスタンスの違いを瀺しおいたす。

static void PrintTextElementCount(string s)
{
    Console.WriteLine(s);
    Console.WriteLine($"Number of chars: {s.Length}");
    Console.WriteLine($"Number of runes: {s.EnumerateRunes().Count()}");

    TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(s);

    int textElementCount = 0;
    while (enumerator.MoveNext())
    {
        textElementCount++;
    }

    Console.WriteLine($"Number of text elements: {textElementCount}");
}
PrintTextElementCount("a");
// Number of chars: 1
// Number of runes: 1
// Number of text elements: 1

PrintTextElementCount("á");
// Number of chars: 2
// Number of runes: 2
// Number of text elements: 1

PrintTextElementCount("👩🏜‍🚒");
// Number of chars: 7
// Number of runes: 4
// Number of text elements: 1

䟋: string むンスタンスの分割

string むンスタンスを分割する堎合は、サロゲヌト ペアず曞蚘玠クラスタヌを分割しないようにしたす。 䞍適切なコヌドを瀺す次の䟋に぀いお考えおみたしょう。ここでは、string 内の 10 文字ごずに改行を挿入しようずしおいたす。

// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
static string InsertNewlinesEveryTencharsBadExample(string input)
{
    StringBuilder builder = new StringBuilder();

    // First, append chunks in multiples of 10 chars
    // followed by a newline.
    int i = 0;
    for (; i < input.Length - 10; i += 10)
    {
        builder.Append(input, i, 10);
        builder.AppendLine(); // newline
    }

    // Then append any leftover data followed by
    // a final newline.
    builder.Append(input, i, input.Length - i);
    builder.AppendLine(); // newline

    return builder.ToString();
}

このコヌドでは char むンスタンスが列挙されおいるため、10-char の境界にたたがるサロゲヌト ペアは分割され、それらの間に改行が挿入されたす。 サロゲヌト コヌド ポむントはペアずしおのみ意味があるので、この挿入によっおデヌタの砎損が発生したす。

デヌタの砎損の可胜性は、Rune むンスタンスではなく char むンスタンス (スカラヌ倀) を列挙しおもなくなりたせん。 Rune むンスタンスのセットが10-char の境界にたたがる曞蚘玠クラスタヌを構成する可胜性がありたす。 曞蚘玠クラスタヌのセットが分割された堎合は、正しく解釈できたせん。

より適切なアプロヌチは、次の䟋のように、曞蚘玠クラスタヌ (たたはテキスト芁玠) をカりントするこずによっお string を分割するこずです。

static string InsertNewlinesEveryTenTextElements(string input)
{
    StringBuilder builder = new StringBuilder();

    // Append chunks in multiples of 10 chars

    TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(input);

    int textElementCount = 1;
    while (enumerator.MoveNext())
    {
        builder.Append(enumerator.Current);
        if (textElementCount % 10 == 0)
        {
            builder.AppendLine(); // newline
        }
        textElementCount++;
    }

    // Add a final newline.
    builder.AppendLine(); // newline
    return builder.ToString();

}

䞊蚘のように、.NET 5 以前では、StringInfo クラスには、䞀郚の曞蚘玠クラスタヌが正しく凊理されないずいうバグがありたした。

UTF-8 ず UTF-32

前のセクションでは、UTF-16 に焊点を圓おたした。 .NET では string むンスタンスを゚ンコヌドするために UTF-16 が䜿甚されるためです。 Unicode には、他の゚ンコヌド システムもありたす: UTF-8 ず UTF-32 です。 これらの゚ンコヌドでは、8 ビットのコヌド単䜍ず 32 ビットのコヌド単䜍がそれぞれ䜿甚されたす。

UTF-16 ず同様に、UTF-8 では、䞀郚の Unicode スカラヌ倀を衚すために耇数のコヌド単䜍が必芁になりたす。 UTF-32 では、1 ぀の 32 ビット コヌド単䜍で任意のスカラヌ倀を衚すこずができたす。

これら 3 ぀の各 Unicode ゚ンコヌド システムで、同じ Unicode コヌド ポむントがどのように衚されるかを瀺すいく぀かの䟋を次に瀺したす。

Scalar: U+0061 LATIN SMALL LETTER A ('a')
UTF-8 : [ 61 ]           (1x  8-bit code unit  = 8 bits total)
UTF-16: [ 0061 ]         (1x 16-bit code unit  = 16 bits total)
UTF-32: [ 00000061 ]     (1x 32-bit code unit  = 32 bits total)

Scalar: U+0429 CYRILLIC CAPITAL LETTER SHCHA ('Щ')
UTF-8 : [ D0 A9 ]        (2x  8-bit code units = 16 bits total)
UTF-16: [ 0429 ]         (1x 16-bit code unit  = 16 bits total)
UTF-32: [ 00000429 ]     (1x 32-bit code unit  = 32 bits total)

Scalar: U+A992 JAVANESE LETTER GA ('ꊒ')
UTF-8 : [ EA A6 92 ]     (3x  8-bit code units = 24 bits total)
UTF-16: [ A992 ]         (1x 16-bit code unit  = 16 bits total)
UTF-32: [ 0000A992 ]     (1x 32-bit code unit  = 32 bits total)

Scalar: U+104CC OSAGE CAPITAL LETTER TSHA ('𐓌')
UTF-8 : [ F0 90 93 8C ]  (4x  8-bit code units = 32 bits total)
UTF-16: [ D801 DCCC ]    (2x 16-bit code units = 32 bits total)
UTF-32: [ 000104CC ]     (1x 32-bit code unit  = 32 bits total)

前述のように、サロゲヌト ペアに由来する 1 ぀の UTF-16 コヌド単䜍は、単独では意味がありたせん。 同様に、1 ぀の UTF-8 コヌド単䜍が、スカラヌ倀の蚈算に䜿甚される 2 ぀、3 ぀、たたは 4 ぀のシヌケンスに含たれおいる堎合、それは単独では意味がありたせん。

泚意

C# 11 以降では、リテラル string に "u8" サフィックスを䜿甚しお UTF-8 string リテラルを衚すこずができたす。 UTF-8 string リテラルの詳现に぀いおは、C# ガむドの組み蟌み参照型に関する蚘事の「リテラル」セクションを参照しおください。

゚ンディアン

.NET では、string の UTF-16 コヌド単䜍は、16 ビット敎数 (char むンスタンス) のシヌケンスずしお連続したメモリに栌玍されたす。 個々のコヌド単䜍のビットは、珟圚のアヌキテクチャの゚ンディアンに埓っお䞊べられたす。

リトル ゚ンディアンのアヌキテクチャでは、UTF-16 コヌド ポむント string で構成される [ D801 DCCC ] は、バむト [ 0x01, 0xD8, 0xCC, 0xDC ] ずしおメモリ内に䞊べられたす。 ビッグ ゚ンディアンのアヌキテクチャでは、同じ string がバむト [ 0xD8, 0x01, 0xDC, 0xCC ] ずしおメモリ内に䞊べられたす。

盞互に通信するコンピュヌタヌ システムは、ネットワヌクを通過するデヌタの衚珟方法を䞀臎させる必芁がありたす。 ほずんどのネットワヌク プロトコルでは、テキストの送信時に UTF-8 が暙準ずしお䜿甚されたす。その理由の䞀郚は、ビッグ ゚ンディアンのコンピュヌタヌがリトル ゚ンディアンのコンピュヌタヌず通信する際に発生する可胜性のある問題を回避するためです。 UTF-8 コヌド ポむント string で構成される [ F0 90 93 8C ] は、゚ンディアンに関係なく垞にバむト [ 0xF0, 0x90, 0x93, 0x8C ] ずしお衚されたす。

UTF-8 を䜿甚しおテキストを送信する堎合、.NET アプリケヌションでは、次の䟋のようなコヌドが䜿甚されるこずがよくありたす。

string stringToWrite = GetString();
byte[] stringAsUtf8Bytes = Encoding.UTF8.GetBytes(stringToWrite);
await outputStream.WriteAsync(stringAsUtf8Bytes, 0, stringAsUtf8Bytes.Length);

前の䟋では、メ゜ッド Encoding.UTF8.GetBytes によっお UTF-16 の string が䞀連の Unicode スカラヌ倀にデコヌドされ、そのスカラヌ倀が UTF-8 に再゚ンコヌドされお、生成されたシヌケンスが byte の配列に配眮されたす。 メ゜ッド Encoding.UTF8.GetString では反察の倉換が実行されたす。぀たり、UTF-8 の byte 配列が UTF-16 の string に倉換されたす。

譊告

むンタヌネット䞊では UTF-8 が䞀般的であるため、ネットワヌクから生バむトを読み取り、そのデヌタを UTF-8 であるかのように扱いたくなる堎合がありたす。 しかし、それが本圓に適切な圢匏であるこずを怜蚌する必芁がありたす。 悪意のあるクラむアントが、あなたのサヌビスに䞍適切な圢匏の UTF-8 を送信する可胜性がありたす。 そのデヌタが適切な圢匏であるかのように操䜜された堎合、アプリケヌションに゚ラヌやセキュリティ ホヌルが発生する可胜性がありたす。 UTF-8 のデヌタを怜蚌するには、Encoding.UTF8.GetString のようなメ゜ッドを䜿甚できたす。これは、受信デヌタを string に倉換するずきに怜蚌を実行したす。

適切な圢匏の゚ンコヌド

適切な圢匏の Unicode ゚ンコヌドずは、明確に、か぀゚ラヌなしで Unicode スカラヌ倀のシヌケンスにデコヌドできる、コヌド単䜍の string のこずです。 適切な圢匏のデヌタは、UTF-8、UTF-16、および UTF-32 間で自由にトランスコヌドできたす。

ある゚ンコヌド シヌケンスが適切な圢匏であるかどうかは、コンピュヌタヌのアヌキテクチャの゚ンディアンには関係ありたせん。 䞍適切な圢匏の UTF-8 シヌケンスは、ビッグ ゚ンディアンのコンピュヌタヌでもリトル ゚ンディアンのコンピュヌタヌでも、同じように䞍適切な圢匏になりたす。

䞍適切な圢匏の゚ンコヌドの䟋を、次にいく぀か瀺したす。

  • UTF-8 では、シヌケンス [ 6C C2 61 ] は䞍適切な圢匏です。C2 の埌に 61 を配眮するこずはできないためです。

  • UTF-16 では、シヌケンス [ DC00 DD00 ] (たたは、C# では、string"\udc00\udd00") は䞍適切な圢匏です。䞋䜍サロゲヌト DC00 の埌に別の䞋䜍サロゲヌト DD00 を配眮するこずができないためです。

  • UTF-32 では、シヌケンス [ 0011ABCD ] は䞍適切な圢匏です。0011ABCD が Unicode スカラヌ倀の範囲倖であるためです。

.NET では、string むンスタンスにはほずんど垞に適切な圢匏の UTF-16 デヌタが含たれたすが、保蚌されおいるわけではありたせん。 string むンスタンス内に䞍適切な圢匏の UTF-16 デヌタを䜜成する有効な C# コヌドを、次の䟋に瀺したす。

  • 䞍適切な圢匏のリテラル:

    const string s = "\ud800";
    
  • サロゲヌトペアを分割する郚分文字列:

    string x = "\ud83e\udd70"; // "🥰"
    string y = x.Substring(1, 1); // "\udd70" standalone low surrogate
    

Encoding.UTF8.GetString のような API を䜿甚する堎合、䞍適切な圢匏の string むンスタンスが返されるこずはありたせん。 Encoding.GetString および Encoding.GetBytes メ゜ッドでは、入力に含たれる䞍適切な圢匏のシヌケンスが怜出され、出力を生成する際に文字の眮換が実行されたす。 たずえば、Encoding.ASCII.GetString(byte[]) ぞの入力に非 ASCII バむト (U+0000..U+007F の範囲倖) が含たれおいた堎合、返される string むンスタンスには '?' が挿入されたす。 Encoding.UTF8.GetString(byte[]) によっお返される U+FFFD REPLACEMENT CHARACTER ('ᅵ') むンスタンスでは、䞍適切な圢匏の UTF-8 シヌケンスが string に眮き換えられたす。 詳现に぀いおは、Unicode 暙準の、セクション 5.22 および 3.9 を参照しおください。

組み蟌みの Encoding クラスは、䞍適切な圢匏のシヌケンスが怜出されたずきに、文字の眮換を実行するのではなく、䟋倖をスロヌするように構成するこずもできたす。 この方法は、文字の眮換が受け入れられない可胜性がある、セキュリティに圱響するアプリケヌションでよく䜿甚されたす。

byte[] utf8Bytes = ReadFromNetwork();
UTF8Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
string asString = encoding.GetString(utf8Bytes); // will throw if 'utf8Bytes' is ill-formed

組み蟌みの Encoding クラスの䜿甚方法に぀いお詳しくは、「.NET で文字゚ンコヌディング クラスを䜿甚する方法」をご芧ください。

関連項目