Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a cikk bemutatja a .NET által használt karakterkódoló rendszereket. A cikk bemutatja, hogyan működnek a UnicodeStringChar, az UTF-16 és Rune az StringInfoUTF-8 típusok.
A karakter kifejezést itt annak általános értelmében használják, hogy az olvasó mit érzékel egyetlen megjelenítési elemként. Gyakori példák az "a" betű, a "@" szimbólum és az emoji "🐂". Néha az egy karakternek tűnő karakter valójában több független megjelenítési elemből áll, ahogy azt a grafémafürtök szakasza is ismerteti.
Az string és a char típusok
Az string osztály egy példánya szöveget képvisel. Az A string logikailag 16 bites értékek sorozata, amelyek mindegyike a char szerkezet egy-egy példánya. A string.Length tulajdonság a string példány char példányainak számát adja vissza.
Az alábbi mintafüggvény kiírja a char-beli összes string értéket hexadecimális jelöléssel.
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();
}
Adja át a string "Hello" értéket ennek a függvénynek, és a következő kimenetet kapja:
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')
Minden karaktert egyetlen char érték jelöl. Ez a minta a világ legtöbb nyelvére igaz. Például itt van két kínai karakter jelentése, amelyek úgy hangzanak, mint nǐ hǎo és azt jelentik, hogy hello:
PrintChars("你好");
"你好".Length = 2
s[0] = '你' ('\u4f60')
s[1] = '好' ('\u597d')
Egyes nyelveknél, valamint egyes szimbólumok és hangulatjelek esetében azonban két char példány szükséges egyetlen karakter megjelenítéséhez. Például hasonlítsa össze a karaktereket és char példányokat abban a szóban, ami az Osage jelentése az Osage nyelvben.
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')
Az előző példában a szóköz kivételével minden karaktert két char példány jelöl.
Egyetlen Unicode emojit két chars is jelöl, ahogy az alábbi példában látható egy ökör emoji:
"🐂".Length = 2
s[0] = '�' ('\ud83d')
s[1] = '�' ('\udc02')
Ezek a példák azt mutatják, hogy a példányok számát string.Length jelző érték charnem feltétlenül jelzi a megjelenített karakterek számát. Egyetlen char példány önmagában nem feltétlenül jelöl karaktert.
Azokat char a párokat, amelyek egyetlen karakterre vannak képezve, helyettesítő pároknak nevezzük. A működésük megértéséhez ismernie kell a Unicode és az UTF-16 kódolást.
Unicode-kódpontok
A Unicode egy nemzetközi kódolási szabvány, amely különböző platformokon és különböző nyelveken és szkriptekben használható.
A Unicode Standard több mint 1,1 millió kódpontot határoz meg. A kódpont egy egész szám, amely 0 U+10FFFF és (decimális 1 114 1111) között lehet. Egyes kódpontok betűkhez, szimbólumokhoz vagy emojikhoz vannak rendelve. Mások olyan műveletekhez vannak rendelve, amelyek szabályozzák a szöveg vagy a karakterek megjelenítését, például egy új sorra való ugrást. Sok kódpont még nincs hozzárendelve.
Íme néhány példa a kódpont-hozzárendelésekre, amelyekben Unicode-diagramokra mutató hivatkozások találhatók:
| Decimális | Hexadecimális | Példa | Leírás |
|---|---|---|---|
| 10 | U+000A |
n/a | VONALCSATORNA |
| 97 | U+0061 |
egy | LATIN KISBETŰ A |
| 562 | U+0232 |
Ȳ | LATIN NAGYBETŰ Y MACRONNAL |
| 68,675 | U+10C43 |
𐱃 | RÉGI TÜRK BETŰ ORKHON AT |
| 127,801 | U+1F339 |
🌹 | ROSE emoji |
A kódpontokra szokás hivatkozni a szintaxis U+xxxxhasználatával, ahol xxxx a hexán kódolt egész szám értéke van.
A kódpontok teljes tartományán belül két altartomány található:
- Az alapszintű többnyelvű sík (BMP) a tartományban
U+0000..U+FFFF. Ez a 16 bites tartomány 65 536 kódpontot biztosít, ami elegendő ahhoz, hogy lefedje a világ írási rendszereinek többségét. - A kiegészítő kódpontok a tartományban
U+10000..U+10FFFF. Ez a 21 bites tartomány több mint egymillió további kódpontot biztosít, amelyek kevésbé ismert nyelvekhez és más célokra, például emojikhoz használhatók.
Az alábbi ábra a BMP és a kiegészítő kódpontok közötti kapcsolatot mutatja be.
UTF-16 kódegységek
A 16 bites Unicode-átalakítási formátum (UTF-16) egy karakterkódoló rendszer, amely 16 bites kódegységeket használ a Unicode-kódpontok megjelenítéséhez. A .NET az UTF-16 használatával kódolja a szövegeket egy karakterláncban string. A char példányok egy 16 bites kódegységet jelölnek.
Egyetlen 16 bites kódegység az alapszintű többnyelvű sík 16 bites tartományának bármely kódpontját képviselheti. A kiegészítő tartomány kódpontjaihoz azonban két char példányra van szükség.
Helyettesítő párok
A két 16 bites érték egyetlen 21 bites értékre való fordítását egy speciális tartomány, az úgynevezett helyettesítő kódpontok segítik elő, U+D800U+DFFF amelyek között a (decimális 55 296 és 57 343 közötti) értékek szerepelnek.
Az alábbi ábra a BMP és a helyettesítő kódpontok közötti kapcsolatot mutatja be.
Ha egy magas helyettesítő kódpontot (U+D800..U+DBFF) azonnal követ egy alacsony helyettesítő kódpont (U+DC00..U+DFFF), a párt kiegészítő kódpontként értelmezzük az alábbi képlettel.
code point = 0x10000 +
((high surrogate code point - 0xD800) * 0x0400) +
(low surrogate code point - 0xDC00)
Ugyanez a képlet decimális jelöléssel:
code point = 65,536 +
((high surrogate code point - 55,296) * 1,024) +
(low surrogate code point - 56,320)
A magas helyettesítő kódpontnak nincs nagyobb számértéke, mint egy alacsony helyettesítő kódpontnak. A magas helyettesítő kódpont neve "magas", mivel a 20 bites kódponttartomány magasabbrendű 10 bitjének kiszámítására szolgál. Az alacsony helyettesítő kódpont az alacsonyabb rendű 10 bit kiszámítására szolgál.
Például a helyettesítő párnak 0xD83C megfelelő tényleges kódpont, amely 0xDF39 a következőképpen van kiszámítva:
actual = 0x10000 + ((0xD83C - 0xD800) * 0x0400) + (0xDF39 - 0xDC00)
= 0x10000 + ( 0x003C * 0x0400) + 0x0339
= 0x10000 + 0xF000 + 0x0339
= 0x1F339
Ugyanez a számítás decimális jelöléssel:
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
Az előző példa azt mutatja be, hogy "\ud83c\udf39" a korábban említett kódpont UTF-16 kódolása U+1F339 ROSE ('🌹') .
Unicode skaláris értékek
A Unicode skaláris érték kifejezés a helyettesítő kódpontoktól eltérő összes kódpontra vonatkozik. Más szóval a skaláris érték bármely olyan kódpont, amely egy karakterhez van hozzárendelve, vagy a jövőben hozzárendelhető egy karakterhez. A "Karakter" itt mindenre utal, amely hozzárendelhető egy kódponthoz, beleértve például a szöveg vagy a karakterek megjelenítését vezérlő műveleteket.
Az alábbi ábra a skaláris érték kódpontjait szemlélteti.
A Rune típus skaláris értékként
Fontos
A Rune típus nem érhető el a .NET-keretrendszerben.
A .NET-ben a System.Text.Rune típus Unicode skaláris értéket jelöl.
A Rune konstruktorok ellenőrzik, hogy az eredményül kapott példány érvényes Unicode skaláris érték-e, ellenkező esetben kivételt okoznak. Az alábbi példa olyan kódot mutat be, amely sikeresen példányosítja a Rune példányokat, mivel a bemenet érvényes skaláris értékeket tartalmaz.
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');
Az alábbi példa kivételt jelez, mert a kódpont a helyettesítő tartományban van, és nem része helyettesítő párnak:
Rune f = new Rune('\ud801');
Az alábbi példa kivételt jelez, mert a kódpont túllépi a kiegészítő tartományt:
Rune g = new Rune(0x12345678);
Rune használati példa: betűk kis- és nagybetűssé alakítása
Egy olyan API, amely egy char skaláris értéket tartalmazó kódponttal dolgozik, nem működik megfelelően, ha az char helyettesítő párból származik. Vegyük például a következő metódust, amely minden egyes char-t meghívja a string-ben:
// 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();
}
Ha a inputstring kisbetűs Deseret betűt er (𐑉) tartalmazza, ez a kód nem konvertálja nagybetűvé 𐐡. A kód minden helyettesítő kódponton külön hív char.ToUpperInvariant , U+D801 és U+DC49. De U+D801 önmagában nem rendelkezik elegendő információval ahhoz, hogy kisbetűként azonosítsa, ezért char.ToUpperInvariant hagyja békén. És ugyanúgy kezeli U+DC49 . Az eredmény az, hogy a inputstring "𐑉" kisbetű nem lesz "𐑉" nagybetűssé konvertálva.
Íme két lehetőség a string helyes nagybetűs átalakítására:
Hívja meg a String.ToUpperInvariant, a string bemeneten ahelyett, hogy
char-by-chariterálna. Astring.ToUpperInvariantmetódus hozzáféréssel rendelkezik az egyes helyettesítő párok mindkét részéhez, így minden Unicode-kódpontot megfelelően kezelhet.A Unicode skaláris értékeit
Runepéldányokként iteráljuk, nem pedigcharpéldányokként, ahogy az alábbi példában látható. Mivel aRunepéldány érvényes Unicode skaláris érték, átadható az API-knak, amelyek várhatóan skaláris értéken fognak működni. A következő példában látható hívás Rune.ToUpperInvariant például helyes eredményeket ad: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(); }
Egyéb Rune API-k
A Rune típus számos char API analógjait teszi elérhetővé. A következő metódusok például statikus API-kat tükröznek a char típuson:
A Rune példányból a nyers skaláris érték lekéréséhez használja a Rune.Value tulajdonságot.
A Rune példányt vissza lehet konvertálni char sorozattá a Rune.ToString vagy Rune.EncodeToUtf16 módszer használatával.
Mivel bármely Unicode skaláris érték egyetlen char vagy helyettesítő pár által ábrázolható, a Rune példányokat legfeljebb 2 char példány jelölheti. A Rune.Utf16SequenceLength használatával megnézheti, hogy hány char példányra van szükség egy Rune példány reprezentálásához.
A .NET Rune típusával kapcsolatos további információkért tekintse meg az Rune API-hivatkozást.
Grapheme-fürtök
Egy karakter akár több kódpont kombinációjából is állhat, ezért a "karakter" helyett gyakran használt leíróbb kifejezés a graféma-csoport. A szövegelem a .NET megfelelő kifejezése.
Vegye figyelembe az "a string ", "á", "á" és "👩🏽🚒" példányokat. Ha az operációs rendszer a Unicode szabvány által meghatározott módon kezeli őket, mindegyik string példány egyetlen szöveges elemként vagy gráffürtként jelenik meg. Az utolsó kettőt azonban egynél több skaláris értékkódpont jelöli.
Az string "a"-t egy skaláris érték jelöli, és egy példányt
chartartalmaz.U+0061 LATIN SMALL LETTER A
Az string "á"-t egy skaláris értékkel jelölik, és tartalmaz egy példányt
char.U+00E1 LATIN SMALL LETTER A WITH ACUTE
Az string "á" ugyanúgy néz ki, mint az "á", de két skaláris érték jelöli, és két
charpéldányt tartalmaz.U+0061 LATIN SMALL LETTER AU+0301 COMBINING ACUTE ACCENT
Végül a string "
👩🏽🚒" értékét négy skaláris érték jelöli, és hétcharpéldányt tartalmaz.-
U+1F469 WOMAN(kiegészítő tartomány, pótpárt igényel) -
U+1F3FD EMOJI MODIFIER FITZPATRICK TYPE-4(kiegészítő tartomány, pótpárt igényel) U+200D ZERO WIDTH JOINER-
U+1F692 FIRE ENGINE(kiegészítő tartomány, pótpárt igényel)
-
Néhány fenti példában - például a kombináló ékezetmódosító vagy a bőrtónus módosító - a kódpont nem jelenik meg önálló elemként a képernyőn. Ehelyett egy előtte lévő szövegelem megjelenését módosítja. Ezek a példák azt mutatják, hogy több skaláris értékre is szükség lehet ahhoz, hogy egyetlen "karakterként" vagy "grapheme-fürtként" definiáljuk azt, amit gondolunk.
Egy string gráfém csoportok felsorolásához használja a StringInfo osztályt, ahogyan az alábbi példában látható. Ha ismeri a Swiftet, a .NET StringInfo típus fogalmilag hasonló a Swift típusáhozcharacter.
Példa: darabszám char, Runeés szövegelem-példányok
A .NET API-kban a gráffürtöt szöveges elemnek nevezzük. Az alábbi módszer bemutatja a char, Rune és szövegelem példányok közötti különbségeket egy string-ben.
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
Példa: string példányok felosztása
Példányok felosztásakor string kerülje el a helyettesítő párok felosztását és a gráféma klaszterek felosztását. Tekintse meg a következő példát a helytelen kódra, amely 10 karakterenként szeretne sortöréseket beszúrni a stringkövetkezőbe:
// 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();
}
Mivel ez a kód számba char veszi a példányokat, egy helyettesítő pár, amely történetesen egy 10-határtchar keresztez, fel lesz osztva, és egy új vonal lesz beszúrva közöttük. Ez a beszúrás adatsérülést vezet be, mivel a helyettesítő kódpontok csak párként értelmezhetők.
Az adatsérülés lehetősége nem szűnik meg, ha Rune példányokat (skaláris értékeket) sorol fel a char példányok helyett. A Rune példányok halmaza olyan grafémacsoportot alkothat, amely átfed egy 10-char határt. Ha a gráffürt-készlet fel van osztva, az nem értelmezhető megfelelően.
A jobb módszer a string gráffürtök vagy szöveges elemek számlálásával történő megtörése, ahogyan az alábbi példában is látható:
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();
}
Ahogy korábban említettük, a .NET 5 előtt az StringInfo osztályban hiba történt, ami miatt néhány gráffürt helytelenül lett kezelve.
UTF-8 és UTF-32
Az előző szakaszok az UTF-16 formátumra koncentráltak, mert a .NET ezt használja a string példányok kódolásához. Vannak más kódolási rendszerek a Unicode - UTF-8 és UTF-32. Ezek a kódolások 8 bites kódegységeket és 32 bites kódegységeket használnak.
Az UTF-16-hoz hasonlóan az UTF-8-hoz is több kódegységre van szükség bizonyos Unicode skaláris értékek megjelenítéséhez. Az UTF-32 bármilyen skaláris értéket képviselhet egyetlen 32 bites kódegységben.
Íme néhány példa arra, hogyan jelenik meg ugyanaz a Unicode-kódpont a három Unicode kódolási rendszer mindegyikében:
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)
Ahogy korábban említettük, egyetlen UTF-16 kódegység egy helyettesítő párból önmagában értelmetlen. Ugyanígy egyetlen UTF-8 kódegység önmagában is értelmetlen, ha egy skaláris érték kiszámításához két, három vagy négy sorozatban van.
Megjegyzés
A C# 11-től kezdve az UTF-8 string literálokat az "u8" utótaggal jelölheti egy literálon string. Az UTF-8 string literálokkal kapcsolatos további információkért tekintse meg a C# útmutató beépített referenciatípusait string ismertető cikk "literálok" szakaszát.
Bájt sorrendösség
A .NET-ben az UTF-16 kódegységek string egybefüggő memóriában vannak tárolva, 16 bites egész számok (char példányok) sorozataként. Az egyes kódegységek bitjei az aktuális architektúra endianitásának megfelelően vannak meghatározva.
A little-endian architektúrán az string UTF-16 kódpontokból álló [ D801 DCCC ] a memóriában bájtokként [ 0x01, 0xD8, 0xCC, 0xDC ] kerülne elrendezésre. Egy big-endian architektúrán a string ugyanúgy kerülne elhelyezésre a memóriában, mint a bájtok [ 0xD8, 0x01, 0xDC, 0xCC ].
Az egymással kommunikáló számítógépes rendszereknek meg kell egyeznie a vezetéken áthaladó adatok ábrázolásában. A legtöbb hálózati protokoll az UTF-8 szabványt használja a szövegek továbbításához, részben azért, hogy elkerülje azokat a problémákat, amelyek egy kis endian géppel kommunikáló big endian gépekből eredhetnek. Az string UTF-8 kódpontokból álló kódpontok [ F0 90 93 8C ] mindig bájtként [ 0xF0, 0x90, 0x93, 0x8C ] jelennek meg, függetlenül az endianitástól.
Ha az UTF-8-at szeretné használni a szöveg továbbításához, a .NET-alkalmazások gyakran az alábbi példához hasonló kódot használnak:
string stringToWrite = GetString();
byte[] stringAsUtf8Bytes = Encoding.UTF8.GetBytes(stringToWrite);
await outputStream.WriteAsync(stringAsUtf8Bytes, 0, stringAsUtf8Bytes.Length);
Az előző példában az Encoding.UTF8.GetBytes metódus visszaalakítja a UTF-16 kódolást Unicode skaláris értékek sorozatává, majd ezeket a skaláris értékeket újra kódolja UTF-8 formátumba, és az így kapott sorozatot egy tömbbe helyezi. A Encoding.UTF8.GetString metódus az ellenkező átalakítást hajtja végre, és UTF-8 byte tömböt konvertál UTF-16-rastring.
Figyelmeztetés
Mivel az UTF-8 köznapi az interneten, csábító lehet nyers bájtokat olvasni a vezetékből, és úgy kezelni az adatokat, mintha UTF-8 lenne. Azonban ellenőrizze, hogy valóban megfelelően van-e kialakítva. Előfordulhat, hogy egy rosszindulatú ügyfél rosszul formázott UTF-8-at küld a szolgáltatásnak. Ha úgy használja az adatokat, mintha azok megfelelően lettek volna formázva, az hibákat vagy biztonsági réseket okozhat az alkalmazásban. Az UTF-8-adatok érvényesítéséhez használhat egy olyan metódust mint Encoding.UTF8.GetString, amely érvényesítést hajt végre, miközben a bejövő adatokat átalakítja egy string-re.
Jól formázott kódolás
A jól formázott Unicode-kódolás olyan kódegységsorozat, amely egyértelműen és hiba nélkül dekódolható Unicode skaláris értékek sorozatává. A jól formázott adatok szabadon átkódolhatók az UTF-8, az UTF-16 és az UTF-32 között.
Az a kérdés, hogy egy kódolási sorozat jól formázott-e vagy sem, nem függ a gép architektúrájának végiségétől. Egy rosszul formázott UTF-8 sorozat mind a big-endian, mind a little-endian gépeken ugyanúgy rosszul van formázva.
Íme néhány példa a nem formázott kódolásokra:
Az UTF-8-ban a sorozat
[ 6C C2 61 ]helytelen, mertC2-t nem követheti61.Az UTF-16-ban a
[ DC00 DD00 ]szekvencia (vagy C#-ban az string"\udc00\udd00"szekvencia) rossz formátumú, mert az alacsony helyettesítő karakterDC00nem követhető egy másik alacsony helyettesítő karakterrelDD00.Az UTF-32-ben a sorozat
[ 0011ABCD ]helytelenül megformált, mert0011ABCDkívül esik a Unicode skaláris értékeinek tartományán.
A .NET-ben a string példányok szinte mindig jól formázott UTF-16 adatokat tartalmaznak, de ez nem garantált. Az alábbi példák érvényes C# kódot mutatnak be, amely hibásan formázott UTF-16 adatokat hoz létre a string példányokban.
Egy rosszul formázott literál:
const string s = "\ud800";Egy alsztring, amely feloszt egy helyettesítési párt.
string x = "\ud83e\udd70"; // "🥰" string y = x.Substring(1, 1); // "\udd70" standalone low surrogate
Az olyan API-k, mint a Encoding.UTF8.GetString, soha nem adnak vissza hibásan formázott string példányokat.
Encoding.GetString és Encoding.GetBytes a metódusok a bemenetben rosszul formázott sorozatokat észlelnek, és a kimenet létrehozásakor karakterhelyettesítést hajtanak végre. Ha például Encoding.ASCII.GetString(byte[]) nem ASCII bájt jelenik meg a bemenetben (az U+0000..U+007F tartományon kívül), a visszaadott string példányba egy "?" értéket szúr be.
Encoding.UTF8.GetString(byte[]) a hibásan formázott UTF-8 sorozatokat a visszaadott string példányban U+FFFD REPLACEMENT CHARACTER ('�')-ra cseréli. További információ : Unicode Standard, 5.22 és 3.9.
A beépített Encoding osztályok úgy is konfigurálhatók, hogy kivételt okozzanak ahelyett, hogy karakterhelyettesítést hajtanak végre, ha rosszul formázott sorozatok jelennek meg. Ezt a megközelítést gyakran használják olyan biztonsági szempontból érzékeny alkalmazásokban, ahol a karakterhelyettesítés nem feltétlenül elfogadható.
byte[] utf8Bytes = ReadFromNetwork();
UTF8Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
string asString = encoding.GetString(utf8Bytes); // will throw if 'utf8Bytes' is ill-formed
A beépített osztályok használatáról további információt a .NET karakterkódoló Encoding osztályainak használata című témakörben talál.