Kódování znaků v rozhraní .NET

Tento článek obsahuje úvod do charsystémů kódování aktérů, které používají .NET. Tento článek vysvětluje, jak Stringfungují typy a kódování CharRuneStringInfo Unicode, UTF-16 a UTF-8.

Pojem character se zde používá v obecném smyslu toho , co čtenář považuje za jediný prvek zobrazení. Mezi běžné příklady patří písmeno "a", symbol "@" a emoji "🐂". Někdy to vypadá jako jeden charaktér se ve skutečnosti skládá z několika nezávislých prvků zobrazení, jak vysvětluje část clusterů grapheme.

Typy a char typy string

Instance string třídy představuje nějaký text. A string je logicky posloupnost 16bitových hodnot, z nichž každá je instancí char struktury. To je . string Vlastnost Length vrátí počet char instancí v string instanci.

Následující ukázková funkce vypíše hodnoty v šestnáctkovém zápisu všech char instancí v :string

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 Předejte funkci "Hello" a zobrazí se následující výstup:

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')

Každý charaktér je reprezentován jednou char hodnotou. Tento vzor platí pro většinu světových jazyků. Tady je například výstup pro dva čínské charaktéry, které zní jako nǐ hǎo a znamenají Hello:

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

V některých jazycích a u některých symbolů a emoji však trvá dvě char instance, které představují jeden charaktér. Porovnejte charnapříklad aktéry a char instance ve slově, které znamená Osage v jazyce Osage :

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')

V předchozím příkladu je každý charaktér s výjimkou mezery reprezentován dvěma char instancemi.

Jedna emoji unicode je také reprezentována dvěma chars, jak je vidět v následujícím příkladu znázorňující emoji ox:

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

Tyto příklady ukazují, že hodnota string.Length, která označuje počet char instancí, nemusí nutně znamenat počet zobrazených charakterů. Jedna char instance sama o sobě nemusí nutně představovat charaktér.

Dvojice char , které se mapují na jeden charaktér, se nazývají náhradní páry. Abyste pochopili, jak fungují, musíte porozumět kódování Unicode a UTF-16.

Body kódu Unicode

Unicode je mezinárodní kódovací standard pro použití na různých platformách a s různými jazyky a skripty.

Standard Unicode definuje více než 1,1 milionu bodů kódu. Bod kódu je celočíselná hodnota, která může být v rozsahu od 0 do U+10FFFF (desítková hodnota 1 114 111). Některé body kódu se přiřazují písmenům, symbolům nebo emoji. Ostatním se přiřazují akce, které určují, jak se budou zobrazovat texty nebo charaktéry, například přejít na nový řádek. Mnoho bodů kódu ještě není přiřazeno.

Tady je několik příkladů přiřazení bodů kódu s odkazy na ts unicode char, ve kterých se zobrazují:

Desetinné číslo Hex Příklad Popis
10 U+000A ODŘÁDKOVÁNÍ
97 U+0061 d MALÉ PÍSMENO LATINKY A
562 U+0232 Ȳ VELKÉ PÍSMENO LATINKY Y S POČÁTEČNÍM PÍSMENEM
68,675 U+10C43 𐱃 STARÉ TURKICKÉ PÍSMENO ORKHON V
127,801 U+1F339 🌹 EMOJI ROSE

Body kódu se obvykle označují pomocí syntaxe U+xxxx, kde xxxx je celočíselná hodnota zakódovaná šestnáctkovým kódem.

V celém rozsahu bodů kódu existují dvě poduspořádky:

  • Základní vícejazyčná rovina (BMP) v rozsahu U+0000..U+FFFF. Tento 16bitový rozsah poskytuje 65 536 bodů kódu, který stačí k pokrytí většiny systémů psaní na světě.
  • Doplňkové body kódu v rozsahu U+10000..U+10FFFF. Tento 21bitový rozsah poskytuje více než milion dalších bodů kódu, které lze použít pro méně známé jazyky a další účely, jako jsou emoji.

Následující diagram znázorňuje vztah mezi BMP a doplňkovými body kódu.

BMP and supplementary code points

Jednotky kódu UTF-16

16bitový formát transformace Unicode (UTF-16) je charsystém kódování acter, který používá 16bitové jednotky kódu k reprezentaci bodů kódu Unicode. .NET používá UTF-16 ke kódování textu v souboru string. Instance char představuje 16bitovou jednotku kódu.

Jedna 16bitová jednotka kódu může představovat libovolný bod kódu v 16bitovém rozsahu základní vícejazyčné roviny. Pro bod kódu v doplňkovém rozsahu jsou však potřeba dvě char instance.

Náhradní páry

Překlad dvou 16bitových hodnot na jednu 21bitovou hodnotu usnadňuje zvláštní rozsah označovaný jako náhradní body kódu od U+D800 do U+DFFF (desítkové číslo 55 296 až 57 343), včetně.

Následující diagram znázorňuje vztah mezi BMP a náhradními body kódu.

BMP and surrogate code points

Pokud je za vysokým náhradním kódovým bodem (U+D800..U+DBFF) okamžitě následovat nízký náhradní kódový bod (U+DC00..U+DFFF), pár se interpretuje jako doplňkový kódový bod pomocí následujícího vzorce:

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

Tady je stejný vzorec, který používá desetinnou notaci:

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

Vysoký náhradní kódový bod nemá vyšší číselnou hodnotu než nízký náhradní kódový bod. Vysoký náhradní kódový bod se nazývá "high", protože se používá k výpočtu vyššího pořadí 10 bitů 20bitového rozsahu bodů kódu. K výpočtu 10 bitů nižšího řádu se používá nízký náhradní bod kódu.

Například skutečný bod kódu, který odpovídá náhradnímu páru 0xD83C , a 0xDF39 vypočítá se následujícím způsobem:

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

Tady je stejný výpočet pomocí desetinného zápisu:

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

Předchozí příklad ukazuje, že "\ud83c\udf39" je kódování U+1F339 ROSE ('🌹') UTF-16 výše uvedeného bodu kódu.

Skalární hodnoty Unicode

Termín Skalární hodnota Unicode odkazuje na všechny jiné body kódu než náhradní body kódu. Jinými slovy, skalární hodnota je jakýkoli bod kódu, který je přiřazen character nebo může být přiřazen charaktér v budoucnu. Znak zde odkazuje na cokoli, co je možné přiřadit k bodu kódu, což zahrnuje například akce, které řídí způsob zobrazení textu nebo characterů.

Následující diagram znázorňuje skalární body kódu hodnoty.

Scalar values

Typ Rune jako skalární hodnota

Počínaje .NET Core 3.0 System.Text.Rune představuje typ skalární hodnotu Unicode. Rune není k dispozici v rozhraní .NET Core 2.x nebo .NET Framework 4.x.

Konstruktory Rune ověřují, že výsledná instance je platná skalární hodnota Unicode, jinak vyvolá výjimku. Následující příklad ukazuje kód, který úspěšně vytvoří Rune instanci instancí, protože vstup představuje platné skalární hodnoty:

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');

Následující příklad vyvolá výjimku, protože bod kódu je v náhradní oblasti a není součástí náhradní dvojice:

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

Následující příklad vyvolá výjimku, protože bod kódu je nad rámec doplňkového rozsahu:

Rune g = new Rune(0x12345678);

Rune Příklad použití: změna písmen

Rozhraní API, které přebírá char a předpokládá, že pracuje s bodem kódu, který je skalární hodnotou, nefunguje správně, pokud char je z náhradní dvojice. Představte si například následující metodu, která volá Char.ToUpperInvariant každou charstringz těchto metod:

// 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();
}

inputstring Pokud obsahuje malá písmena Deseret er (𐑉), tento kód ho nepřevedne na velká písmena (𐐡). Kód volá char.ToUpperInvariant samostatně na každém náhradním bodu U+D801 kódu a U+DC49. Ale U+D801 nemá dostatek informací, aby je identifikoval jako malá písmena, takže char.ToUpperInvariant je ponechá sám. A zvládne U+DC49 to stejným způsobem. Výsledkem je, že se malá písmena 𐑉v inputstring souboru nepřevedou na velká písmena 𐑉.

Tady jsou dvě možnosti správného převodu na velká písmena string :

  • Volání String.ToUpperInvariant vstupu string namísto iterace char-by-char. Metoda string.ToUpperInvariant má přístup k oběma částem každého náhradního páru, takže dokáže správně zpracovat všechny body kódu Unicode.

  • Iterujte skalární hodnoty Unicode jako Rune instance místo char instancí, jak je znázorněno v následujícím příkladu. Rune Vzhledem k tomu, že instance je platná skalární hodnota Unicode, lze ji předat rozhraním API, která očekávají, že budou fungovat na skalární hodnotě. Například volání Rune.ToUpperInvariant , jak je znázorněno v následujícím příkladu, poskytuje správné výsledky:

    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();
    }
    

Jiná Rune rozhraní API

Typ Rune zveřejňuje analogy mnoha char rozhraní API. Například následující metody zrcadlí statická rozhraní API typu char :

K získání nezpracované skalární hodnoty z Rune instance použijte Rune.Value vlastnost.

Chcete-li převést Rune instanci zpět na posloupnost chars, použijte Rune.ToString nebo metodu Rune.EncodeToUtf16 .

Vzhledem k tomu, že skalární hodnota Unicode je reprezentována jedním char nebo náhradním párem, může každá Rune instance reprezentovat maximálně 2 char instance. Umožňuje Rune.Utf16SequenceLength zjistit, kolik char instancí je potřeba k reprezentaci Rune instance.

Další informace o typu .NET Rune najdete v referenčních informacích k Rune rozhraní API.

Clustery Grapheme

Vypadá to, že jeden charaktér může mít za následek kombinaci více bodů kódu, takže popisnější termín, který se často používá místo "character" je cluster grapheme. Ekvivalentní termín v .NET je textový prvek.

Vezměte v string úvahu instance "a", "á", "á" a "👩🏽‍🚒". Pokud je operační systém zpracovává podle standardu Unicode, zobrazí se každá z těchto string instancí jako jeden textový prvek nebo cluster grapheme. Poslední dva jsou ale reprezentovány více než jedním skalárním bodem kódu hodnoty.

  • " string a" je reprezentován jednou skalární hodnotou a obsahuje jednu char instanci.

    • U+0061 LATIN SMALL LETTER A
  • Hodnota string "á" je reprezentována jednou skalární hodnotou a obsahuje jednu char instanci.

    • U+00E1 LATIN SMALL LETTER A WITH ACUTE
  • " string á" vypadá stejně jako "á", ale je reprezentován dvěma skalárními hodnotami a obsahuje dvě char instance.

    • U+0061 LATIN SMALL LETTER A
    • U+0301 COMBINING ACUTE ACCENT
  • Nakonec je "string👩🏽‍🚒" reprezentován čtyřmi skalárními hodnotami a obsahuje sedm char instancí.

    • U+1F469 WOMAN (doplňkový rozsah, vyžaduje náhradní pár)
    • U+1F3FD EMOJI MODIFIER FITZPATRICK TYPE-4 (doplňkový rozsah, vyžaduje náhradní pár)
    • U+200D ZERO WIDTH JOINER
    • U+1F692 FIRE ENGINE (doplňkový rozsah, vyžaduje náhradní pár)

V některých z předchozích příkladů – například kombinace modifikátoru zvýraznění nebo modifikátor tónu kůže – se bod kódu nezobrazuje jako samostatný prvek na obrazovce. Slouží spíše ke změně vzhledu textového prvku, který byl před ním. Tyto příklady ukazují, že může trvat několik skalárních hodnot, aby se shodovaly s jedním "charaktérem" nebo "clusterem grapheme".

K zobrazení výčtu clusterů grafeme v objektu string, použijte StringInfo třídu, jak je znázorněno v následujícím příkladu. Pokud znáte Swift, typ .NET StringInfo je koncepčně podobný typu Swiftucharacter.

Příklad: počet char, Runea instance textových elementů

V rozhraních .NET API se cluster grapheme nazývá textový prvek. Následující metoda ukazuje rozdíly mezi char, Runea text element instance v 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

Pokud tento kód spustíte v rozhraní .NET Framework nebo .NET Core 3.1 nebo starším, zobrazí 4se počet textových prvků pro emoji . Důvodem je chyba ve StringInfo třídě, která je opravena v .NET 5.

Příklad: Rozdělení string instancí

Při rozdělování string instancí nepoužívejte rozdělení náhradních párů a clusterů grafeme. Podívejte se na následující příklad nesprávného kódu, který má v úmyslu vložit konce řádků každých 10 characters v :string

// 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();
}

Vzhledem k tomu, že tento kód vypíše char instance, náhradní dvojice, která se stane, že se rozdělí hranice o 10,char a mezi ně vloží nový řádek. Toto vložení představuje poškození dat, protože náhradní body kódu jsou smysluplné pouze jako páry.

Potenciál poškození dat není eliminován, pokud místo instancí vypíšete Rune instance (skalární hodnoty char ). Sada Rune instancí může vytvořit cluster grapheme, který se váže na 10char hranic. Pokud je sada clusteru grapheme rozdělená, není možné ji správně interpretovat.

Lepším přístupem je přerušit string počítání shluků grafů nebo textových prvků, jak je znázorněno v následujícím příkladu:

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 && textElementCount > 0)
        {
            builder.AppendLine(); // newline
        }
        textElementCount++;
    }

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

}

Jak jsme uvedli dříve, před .NET 5 měla třída chybu, StringInfo která způsobovala nesprávné zpracování některých clusterů grapheme.

UTF-8 a UTF-32

Předchozí části se zaměřily na UTF-16, protože to je to, co .NET používá ke kódování string instancí. Existují další kódovací systémy pro Unicode - UTF-8 a UTF-32. Tato kódování používají 8bitové jednotky kódu a 32bitové jednotky kódu.

Podobně jako UTF-16 vyžaduje UTF-8 několik jednotek kódu, které představují některé skalární hodnoty Unicode. UTF-32 může představovat libovolnou skalární hodnotu v jedné 32bitové jednotce kódu.

Tady je několik příkladů, které ukazují, jak je stejný bod kódu Unicode reprezentován v každém z těchto tří systémů kódování 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)

Jak už bylo zmíněno dříve, jedna jednotka kódu UTF-16 z náhradní dvojice je bezvýznamná sama o sobě. Stejně tak je jedna jednotka kódu UTF-8 bezvýznamná sama o sobě, pokud je v posloupnosti dvou, tří nebo čtyř používaných k výpočtu skalární hodnoty.

Poznámka:

Počínaje jazykem C# 11 můžete reprezentovat literály UTF-8 string pomocí přípony "u8" v literálu string. Další informace o literálech UTF-8 string najdete v části "string literály" článku o integrovaných odkazových typech v příručce jazyka C#.

Endianness

V .NET jsou jednotky string kódu UTF-16 uložené v souvislé paměti jako posloupnost 16bitových celých čísel (char instancí). Bity jednotlivých jednotek kódu jsou rozloženy podle endianness aktuální architektury.

V malé-endové architektuře by string skládající se z bodů kódu [ D801 DCCC ] UTF-16 byly rozloženy do paměti jako bajty [ 0x01, 0xD8, 0xCC, 0xDC ]. Na big-endian architektuře, která by stejná string byla rozložena v paměti jako bajty [ 0xD8, 0x01, 0xDC, 0xCC ].

Počítačové systémy, které spolu komunikují, musí souhlasit s reprezentací dat překračovaných drátem. Většina síťových protokolů používá UTF-8 jako standard při přenosu textu, částečně aby se zabránilo problémům, které můžou mít za následek komunikaci s malým endian počítačem. Složené string z bodů [ F0 90 93 8C ] kódu UTF-8 budou vždy reprezentovány jako bajty [ 0xF0, 0x90, 0x93, 0x8C ] bez ohledu na endianness.

Pokud chcete pro přenos textu použít UTF-8, aplikace .NET často používají kód jako v následujícím příkladu:

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

V předchozím příkladu metoda Encoding.UTF8.GetBytes dekóduje UTF-16 string zpět do řady skalárních hodnot Unicode a pak tyto skalární hodnoty znovu zakóduje do UTF-8 a umístí výslednou sekvenci do byte pole. Metoda Encoding.UTF8.GetString provádí opačnou transformaci a převádí pole UTF-8 byte na UTF-16 string.

Upozorňující

Vzhledem k tomu, že UTF-8 je běžné na internetu, může být lákavé číst nezpracované bajty z drátu a považovat data za UTF-8. Měli byste ale ověřit, že je skutečně správně vytvořený. Škodlivý klient může do vaší služby odeslat špatně formátovaný UTF-8. Pokud s daty pracujete tak, jako by byla dobře vytvořená, mohlo by to způsobit chyby nebo bezpečnostní díry ve vaší aplikaci. K ověření dat UTF-8 můžete použít metodu, jako Encoding.UTF8.GetStringje , která provede ověření při převodu příchozích dat na string.

Kódování ve správném formátu

Kódování Unicode ve správném formátu je string jednotka kódu, která lze jednoznačně dekódovat a bez chyb do posloupnosti skalárních hodnot Unicode. Dobře formátovaná data lze volně překódovat mezi UTF-8, UTF-16 a UTF-32.

Otázka, jestli je sekvence kódování správně vytvořená nebo ne, nesouvisí s endianness architektury počítače. Špatně vytvořená sekvence UTF-8 je špatně vytvořená stejným způsobem jak na big-endianu, tak na malých-endových počítačích.

Tady je několik příkladů kódování ve špatném formátu:

  • V UTF-8 je sekvence [ 6C C2 61 ] špatně vytvořená, protože C2 za ní nelze následovat 61.

  • V UTF-16 je sekvence [ DC00 DD00 ] (nebo v jazyce C#) špatně vytvořená, string"\udc00\udd00"protože nízká náhrada DC00 nemůže být následovana jinou nízkou náhradou DD00.

  • V UTF-32 je sekvence [ 0011ABCD ] špatně vytvořená, protože 0011ABCD je mimo rozsah skalárních hodnot Unicode.

V .NET string instance téměř vždy obsahují dobře formátovaná data UTF-16, ale to není zaručeno. Následující příklady ukazují platný kód jazyka C#, který v instancích vytvoří špatně vytvořená data string UTF-16.

  • Literál s chybným tvarem:

    const string s = "\ud800";
    
  • Dílčí,string který rozdělí náhradní dvojici:

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

Rozhraní API, jako Encoding.UTF8.GetString by nikdy nevracela neformulované string instance. Encoding.GetString a Encoding.GetBytes metody při generování výstupu detekují špatně vytvořené sekvence ve vstupu a provádějí charnahrazování aktérů. Pokud Encoding.ASCII.GetString(byte[]) se například ve vstupu zobrazí bajt bez ASCII (mimo rozsah U+0000..U+007F), vloží do vrácené string instance "?". Encoding.UTF8.GetString(byte[]) nahradí špatně vytvořené sekvence U+FFFD REPLACEMENT CHARACTER ('�') UTF-8 ve vrácené string instanci. Další informace najdete v článcích Standard Unicode, Oddíly 5.22 a 3.9.

Předdefinované Encoding třídy lze také nakonfigurovat tak, aby vyvolaly výjimku místo nahrazení charakteru, pokud jsou zobrazeny špatně vytvořené sekvence. Tento přístup se často používá v aplikacích citlivých na zabezpečení, kde charnáhradní akce nemusí být přijatelné.

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

Informace o tom, jak používat předdefinované třídy, naleznete v Encoding tématu Jak používat chartřídy kódování acter v .NET.

Viz také