Karakterkódolási osztályok használata a .NET-ben
Ez a cikk bemutatja, hogyan használhatja a .NET által a szöveg kódolására és dekódolására szolgáló osztályokat különböző kódolási sémák használatával. Az utasítások feltételezik, hogy elolvasta a .NET-ben a karakterkódolás bevezetési módját.
Kódolók és dekódolók
A .NET kódolási osztályokat biztosít, amelyek különböző kódolási rendszerek használatával kódolnak és dekódolnak szöveget. Az osztály például az UTF8Encoding UTF-8 kódolási és dekódolási szabályait írja le. A .NET UTF-16 kódolást használ (amelyet az UnicodeEncoding osztály jelöl) a string
példányokhoz. A kódolók és dekóderek más kódolási sémákhoz is elérhetők.
A kódolás és a dekódolás érvényesítést is tartalmazhat. Az osztály például UnicodeEncoding ellenőrzi a helyettesítő tartományban lévő összes char
példányt, hogy ellenőrizze, hogy érvényes helyettesítő párokban vannak-e. A tartalék stratégia határozza meg, hogy a kódoló hogyan kezeli az érvénytelen karaktereket, vagy hogy a dekódoló hogyan kezeli az érvénytelen bájtokat.
Figyelmeztetés
A .NET kódolási osztályok lehetővé teszik a karakteradatok tárolását és konvertálását. Nem használhatók bináris adatok sztring formában való tárolására. A használt kódolástól függően a bináris adatok sztringformátummá alakítása a kódolási osztályokkal váratlan viselkedést eredményezhet, és pontatlan vagy sérült adatokat eredményezhet. A bináris adatok sztringűrlaptá alakításához használja a metódust Convert.ToBase64String .
A .NET összes karakterkódolási osztálya örökli az System.Text.Encoding osztályt, amely egy absztrakt osztály, amely meghatározza az összes karakterkódolásra jellemző funkciót. A .NET-ben implementált egyes kódolási objektumok eléréséhez tegye a következőket:
Használja az Encoding osztály statikus tulajdonságait, amelyek a .NET-ben elérhető szabványos karakterkódolásokat (ASCII, UTF-7, UTF-8, UTF-16 és UTF-32) képviselő objektumokat ad vissza. A tulajdonság például Encoding.Unicode egy UnicodeEncoding objektumot ad vissza. Minden objektum helyettesítő tartalék használatával kezeli azokat a sztringeket, amelyeket nem tud kódolni, és bájtokat, amelyeket nem tud dekódolni. További információ: Csere tartalék.
Hívja meg a kódolás osztálykonstruktorát. Az ASCII, az UTF-7, az UTF-8, az UTF-16 és az UTF-32 kódolású objektumok ily módon hozhatók létre. Alapértelmezés szerint minden objektum helyettesítő tartalék használatával kezeli azokat a sztringeket, amelyeket nem tud dekódolni, de megadhat kivételt. További információ: Csere tartalék és kivétel tartalék.
Hívja meg a Encoding(Int32) konstruktort, és adja át a kódolást jelképező egész számot. A standard kódolási objektumok helyettesítő tartalékot használnak, a kódlap és a kétbájtos karakterkészlet (DBCS) kódolási objektumai a legjobban illeszkedő tartalékot használják az olyan sztringek kezelésére, amelyeket nem tudnak kódolni és bájtokat dekódolni. További információkért lásd a legjobban illeszkedő tartalékot.
Hívja meg a metódust Encoding.GetEncoding , amely a .NET-ben elérhető standard, kódlap vagy DBCS-kódolást adja vissza. A túlterhelések lehetővé teszik tartalék objektum megadását a kódolóhoz és a dekóderhez is.
A metódus meghívásával Encoding.GetEncodings a .NET-ben elérhető összes kódolással kapcsolatos információkat lekérheti. A .NET az alábbi táblázatban felsorolt karakterkódolási sémákat támogatja.
Kódolási osztály | Leírás |
---|---|
ASCII | Korlátozott karaktertartományt kódol egy bájt alsó hét bitjének használatával. Mivel ez a kódolás csak a karakterértékeket U+0000 U+007F támogatja, a legtöbb esetben nem megfelelő nemzetközi alkalmazásokhoz. |
UTF-7 | A karaktereket 7 bites ASCII-karakterek sorozataként jelöli. A nem ASCII Unicode karaktereket ASCII-karakterekből álló feloldósorozat jelöli. Az UTF-7 támogatja az olyan protokollokat, mint az e-mail és a hírcsoport. Az UTF-7 azonban nem különösen biztonságos vagy robusztus. Bizonyos esetekben az egy bit módosítása gyökeresen megváltoztathatja egy teljes UTF-7 sztring értelmezését. Más esetekben különböző UTF-7 sztringek kódolhatják ugyanazt a szöveget. A nem ASCII karaktereket tartalmazó sorozatok esetében az UTF-7 több helyet igényel, mint az UTF-8, és a kódolás/dekódolás lassabb. Ezért ha lehetséges, UTF-7 helyett UTF-8-at kell használnia. |
UTF-8 | Minden Unicode-kódpontot 1–4 bájtos sorozatként jelöl. Az UTF-8 támogatja a 8 bites adatméreteket, és számos meglévő operációs rendszerrel jól működik. Az ASCII karaktertartomány esetében az UTF-8 azonos az ASCII kódolással, és szélesebb karakterkészletet tesz lehetővé. A kínai-japán-koreai (CJK)-szkriptek esetében azonban az UTF-8 karakterenként három bájtot igényelhet, és nagyobb adatméretet okozhat, mint az UTF-16. Néha az ASCII-adatok, például a HTML-címkék mennyisége indokolja a CJK-tartomány megnövekedett méretét. |
UTF-16 | Minden Unicode-kódpontot egy vagy két 16 bites egész szám sorozataként jelöl. A leggyakoribb Unicode-karakterekhez csak egy UTF-16 kódpont szükséges, míg a Unicode kiegészítő karakterei (U+10000 és újabbak) két UTF-16 helyettesítő kódpontot igényelnek. A kis- és a nagy végű bájtrendelések egyaránt támogatottak. Az UTF-16 kódolást a közös nyelvi futtatókörnyezet az értékek és String az értékek megjelenítésére Char használja, és a Windows operációs rendszer az értékek megjelenítésére WCHAR használja. |
UTF-32 | Minden Unicode-kódpontot 32 bites egész számként jelöl. A kis- és a nagy végű bájtrendelések egyaránt támogatottak. UTF-32 kódolást akkor használunk, ha az alkalmazások el szeretnék kerülni az UTF-16 kódolás helyettesítő kódpont-viselkedését olyan operációs rendszereken, amelyekhez túl fontos a kódolt terület. A kijelzőn megjelenített egyetlen karakterjelek továbbra is kódolhatók egynél több UTF-32 karakterrel. |
ANSI/ISO-kódolás | Számos kódlaphoz nyújt támogatást. Windows operációs rendszereken a kódlapok egy adott nyelvet vagy nyelvcsoportot támogatnak. A .NET által támogatott kódlapokat felsoroló táblázatot az Encoding osztályban tekintheti meg. A metódus meghívásával Encoding.GetEncoding(Int32) lekérhet egy kódolási objektumot egy adott kódlaphoz. A kódlapok 256 kódpontot tartalmaznak, és nulla alapúak. A legtöbb kódlapon a 0–127 kódpont az ASCII karakterkészletet jelöli, a 128–255 kódpont pedig jelentősen eltér a kódlapok között. Az 1252-as kódlap például latin írási rendszerek karaktereit tartalmazza, beleértve az angol, a német és a francia nyelvet is. Az 1252 kódlap utolsó 128 kódpontja tartalmazza az ékezetes karaktereket. Az 1253-ban kódlap a görög írási rendszerben szükséges karakterkódokat tartalmazza. Az 1253-as kódlap utolsó 128 kódpontja a görög karaktereket tartalmazza. Ennek eredményeképpen az ANSI-kódlapokra támaszkodó alkalmazások nem tárolhatók görög és német nyelven ugyanabban a szöveges streamben, kivéve, ha tartalmaz egy azonosítót, amely a hivatkozott kódlapot jelzi. |
Kétbájtos karakterkészlet (DBCS) kódolása | Támogatja a 256 karakternél több karaktert tartalmazó nyelveket, például a kínait, a japánt és a koreait. A DBCS-ben egy kódpontpár (dupla bájt) jelöli az egyes karaktereket. A Encoding.IsSingleByte tulajdonság a DBCS-kódolások false értékét adja vissza. A metódus meghívásával Encoding.GetEncoding(Int32) lekérhet egy kódolási objektumot egy adott DBCS-hez. Amikor egy alkalmazás kezeli a DBCS-adatokat, a rendszer egy DBCS-karakter első bájtját (az érdeklődő bájtot) az azt követő nyomvonal bájttal együtt dolgozza fel. Mivel a kétbájtos kódpontok egyetlen párja a kódlaptól függően különböző karaktereket jelölhet, ez a séma továbbra sem teszi lehetővé két nyelv, például a japán és a kínai kombinációját ugyanabban az adatfolyamban. |
Ezek a kódolások lehetővé teszik a Unicode-karakterek és az örökölt alkalmazásokban leggyakrabban használt kódolások használatát. Emellett egyéni kódolást is létrehozhat egy olyan osztály definiálásával, amely a tagokból Encoding származik és felül van bírálva.
.NET Core-kódolás támogatása
A .NET Core alapértelmezés szerint nem teszi elérhetővé a 28591 kódlaptól és a Unicode-kódolástól(például UTF-8 és UTF-16) eltérő kódlapkódolásokat. A .NET-et megcélozó szabványos Windows-alkalmazásokban található kódlapkódolásokat azonban hozzáadhatja az alkalmazáshoz. További információkért tekintse meg a témakört CodePagesEncodingProvider .
Kódolási osztály kiválasztása
Ha lehetősége van kiválasztani az alkalmazás által használni kívánt kódolást, akkor unicode kódolást kell használnia, lehetőleg vagy UTF8EncodingUnicodeEncoding. (A.NET támogatja a harmadik Unicode-kódolást is. UTF32Encoding)
Ha ASCII-kódolástASCIIEncoding () tervez használni, válasszon helyette UTF8Encoding . A két kódolás megegyezik az ASCII-karakterkészlettel, de UTF8Encoding az alábbi előnyökkel jár:
Minden Unicode-karaktert képviselhet, míg ASCIIEncoding az U+0000 és az U+007F közötti Unicode-karakterértékeket támogatja.
Hibaészlelést és nagyobb biztonságot nyújt.
Úgy lett hangolva, hogy a lehető leggyorsabb legyen, és gyorsabb legyen, mint bármely más kódolás. Még a teljes mértékben ASCII-t tartalmazó tartalom esetében is gyorsabbak a UTF8Encoding műveletek, mint a .ASCIIEncoding
Érdemes megfontolni, hogy csak régi alkalmazásokhoz használjon ASCIIEncoding . Azonban még az örökölt alkalmazások UTF8Encoding esetében is jobb választás lehet az alábbi okokból (az alapértelmezett beállításokat feltételezve):
Ha az alkalmazás olyan tartalommal rendelkezik, amely nem szigorúan ASCII, és azzal ASCIIEncodingkódolja azt, minden nem ASCII-karakter kérdőjelként (?) kódol. Ha az alkalmazás ezután dekódolja ezeket az adatokat, az adatok elvesznek.
Ha az alkalmazás olyan tartalommal rendelkezik, amely nem szigorúan ASCII, és azzal UTF8Encodingkódolja azt, az eredmény értelmezhetetlennek tűnik, ha ASCII-ként értelmezik. Ha azonban az alkalmazás egy UTF-8 dekóderrel dekódolja ezeket az adatokat, az adatok sikeresen elvégzik a teljes utat.
Egy webalkalmazásban az ügyfélnek egy webes kérésre válaszul küldött karaktereknek tükrözniük kell az ügyfélen használt kódolást. A legtöbb esetben a tulajdonság által visszaadott értékre kell állítania a HttpResponse.ContentEncodingHttpRequest.ContentEncoding tulajdonságot, hogy a felhasználó által várt kódolásban megjelenítse a szöveget.
Kódolási objektum használata
A kódoló egy karaktersorozatot (leggyakrabban Unicode-karaktereket) konvertál numerikus (bájtos) megfelelőjére. Előfordulhat például, hogy ASCII kódolóval konvertálja a Unicode-karaktereket ASCII-vé, hogy azok megjeleníthetők legyenek a konzolon. Az átalakítás végrehajtásához hívja meg a metódust Encoding.GetBytes . Ha meg szeretné határozni, hogy hány bájt szükséges a kódolt karakterek tárolásához a kódolás végrehajtása előtt, meghívhatja a metódust GetByteCount .
Az alábbi példa egyetlen bájttömböt használ a sztringek két különálló műveletben való kódolásához. Egy indexet tart fenn, amely a bájttömb kezdő pozícióját jelzi az ASCII által kódolt bájtok következő készletéhez. Meghívja a ASCIIEncoding.GetByteCount(String) metódust annak biztosítására, hogy a bájttömb elég nagy legyen a kódolt sztring elhelyezéséhez. Ezután meghívja a metódust a ASCIIEncoding.GetBytes(String, Int32, Int32, Byte[], Int32) sztringben lévő karakterek kódolására.
using System;
using System.Text;
public class Example
{
public static void Main()
{
string[] strings= { "This is the first sentence. ",
"This is the second sentence. " };
Encoding asciiEncoding = Encoding.ASCII;
// Create array of adequate size.
byte[] bytes = new byte[49];
// Create index for current position of array.
int index = 0;
Console.WriteLine("Strings to encode:");
foreach (var stringValue in strings) {
Console.WriteLine(" {0}", stringValue);
int count = asciiEncoding.GetByteCount(stringValue);
if (count + index >= bytes.Length)
Array.Resize(ref bytes, bytes.Length + 50);
int written = asciiEncoding.GetBytes(stringValue, 0,
stringValue.Length,
bytes, index);
index = index + written;
}
Console.WriteLine("\nEncoded bytes:");
Console.WriteLine("{0}", ShowByteValues(bytes, index));
Console.WriteLine();
// Decode Unicode byte array to a string.
string newString = asciiEncoding.GetString(bytes, 0, index);
Console.WriteLine("Decoded: {0}", newString);
}
private static string ShowByteValues(byte[] bytes, int last )
{
string returnString = " ";
for (int ctr = 0; ctr <= last - 1; ctr++) {
if (ctr % 20 == 0)
returnString += "\n ";
returnString += String.Format("{0:X2} ", bytes[ctr]);
}
return returnString;
}
}
// The example displays the following output:
// Strings to encode:
// This is the first sentence.
// This is the second sentence.
//
// Encoded bytes:
//
// 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
// 6E 74 65 6E 63 65 2E 20 54 68 69 73 20 69 73 20 74 68 65 20
// 73 65 63 6F 6E 64 20 73 65 6E 74 65 6E 63 65 2E 20
//
// Decoded: This is the first sentence. This is the second sentence.
Imports System.Text
Module Example
Public Sub Main()
Dim strings() As String = {"This is the first sentence. ",
"This is the second sentence. "}
Dim asciiEncoding As Encoding = Encoding.ASCII
' Create array of adequate size.
Dim bytes(50) As Byte
' Create index for current position of array.
Dim index As Integer = 0
Console.WriteLine("Strings to encode:")
For Each stringValue In strings
Console.WriteLine(" {0}", stringValue)
Dim count As Integer = asciiEncoding.GetByteCount(stringValue)
If count + index >= bytes.Length Then
Array.Resize(bytes, bytes.Length + 50)
End If
Dim written As Integer = asciiEncoding.GetBytes(stringValue, 0,
stringValue.Length,
bytes, index)
index = index + written
Next
Console.WriteLine()
Console.WriteLine("Encoded bytes:")
Console.WriteLine("{0}", ShowByteValues(bytes, index))
Console.WriteLine()
' Decode Unicode byte array to a string.
Dim newString As String = asciiEncoding.GetString(bytes, 0, index)
Console.WriteLine("Decoded: {0}", newString)
End Sub
Private Function ShowByteValues(bytes As Byte(), last As Integer) As String
Dim returnString As String = " "
For ctr As Integer = 0 To last - 1
If ctr Mod 20 = 0 Then returnString += vbCrLf + " "
returnString += String.Format("{0:X2} ", bytes(ctr))
Next
Return returnString
End Function
End Module
' The example displays the following output:
' Strings to encode:
' This is the first sentence.
' This is the second sentence.
'
' Encoded bytes:
'
' 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
' 6E 74 65 6E 63 65 2E 20 54 68 69 73 20 69 73 20 74 68 65 20
' 73 65 63 6F 6E 64 20 73 65 6E 74 65 6E 63 65 2E 20
'
' Decoded: This is the first sentence. This is the second sentence.
A dekóder egy adott karakterkódolást tükröző bájttömböt alakít át karakterkészletté egy karaktertömbben vagy egy sztringben. Ha egy bájttömböt karaktertömbbe szeretne dekódolni, hívja meg a metódust Encoding.GetChars . Ha egy bájttömböt sztringgé szeretne dekódolni, hívja meg a metódust GetString . Ha meg szeretné határozni, hogy hány karakterre van szükség a dekódolt bájtok tárolásához a dekódolás végrehajtása előtt, meghívhatja a metódust GetCharCount .
Az alábbi példa három sztringet kódol, majd egyetlen karaktertömbbe dekódolja őket. Egy indexet tart fenn, amely a karaktertömb kezdő pozícióját jelzi a dekódolt karakterek következő készletéhez. Meghívja a GetCharCount metódust annak biztosítására, hogy a karaktertömb elég nagy legyen az összes dekódolt karakter elhelyezéséhez. Ezután meghívja a metódust a ASCIIEncoding.GetChars(Byte[], Int32, Int32, Char[], Int32) bájttömb dekódolásához.
using System;
using System.Text;
public class Example
{
public static void Main()
{
string[] strings = { "This is the first sentence. ",
"This is the second sentence. ",
"This is the third sentence. " };
Encoding asciiEncoding = Encoding.ASCII;
// Array to hold encoded bytes.
byte[] bytes;
// Array to hold decoded characters.
char[] chars = new char[50];
// Create index for current position of character array.
int index = 0;
foreach (var stringValue in strings) {
Console.WriteLine("String to Encode: {0}", stringValue);
// Encode the string to a byte array.
bytes = asciiEncoding.GetBytes(stringValue);
// Display the encoded bytes.
Console.Write("Encoded bytes: ");
for (int ctr = 0; ctr < bytes.Length; ctr++)
Console.Write(" {0}{1:X2}",
ctr % 20 == 0 ? Environment.NewLine : "",
bytes[ctr]);
Console.WriteLine();
// Decode the bytes to a single character array.
int count = asciiEncoding.GetCharCount(bytes);
if (count + index >= chars.Length)
Array.Resize(ref chars, chars.Length + 50);
int written = asciiEncoding.GetChars(bytes, 0,
bytes.Length,
chars, index);
index = index + written;
Console.WriteLine();
}
// Instantiate a single string containing the characters.
string decodedString = new string(chars, 0, index - 1);
Console.WriteLine("Decoded string: ");
Console.WriteLine(decodedString);
}
}
// The example displays the following output:
// String to Encode: This is the first sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
// 6E 74 65 6E 63 65 2E 20
//
// String to Encode: This is the second sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 73 65 63 6F 6E 64 20 73
// 65 6E 74 65 6E 63 65 2E 20
//
// String to Encode: This is the third sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 74 68 69 72 64 20 73 65
// 6E 74 65 6E 63 65 2E 20
//
// Decoded string:
// This is the first sentence. This is the second sentence. This is the third sentence.
Imports System.Text
Module Example
Public Sub Main()
Dim strings() As String = {"This is the first sentence. ",
"This is the second sentence. ",
"This is the third sentence. "}
Dim asciiEncoding As Encoding = Encoding.ASCII
' Array to hold encoded bytes.
Dim bytes() As Byte
' Array to hold decoded characters.
Dim chars(50) As Char
' Create index for current position of character array.
Dim index As Integer
For Each stringValue In strings
Console.WriteLine("String to Encode: {0}", stringValue)
' Encode the string to a byte array.
bytes = asciiEncoding.GetBytes(stringValue)
' Display the encoded bytes.
Console.Write("Encoded bytes: ")
For ctr As Integer = 0 To bytes.Length - 1
Console.Write(" {0}{1:X2}", If(ctr Mod 20 = 0, vbCrLf, ""),
bytes(ctr))
Next
Console.WriteLine()
' Decode the bytes to a single character array.
Dim count As Integer = asciiEncoding.GetCharCount(bytes)
If count + index >= chars.Length Then
Array.Resize(chars, chars.Length + 50)
End If
Dim written As Integer = asciiEncoding.GetChars(bytes, 0,
bytes.Length,
chars, index)
index = index + written
Console.WriteLine()
Next
' Instantiate a single string containing the characters.
Dim decodedString As New String(chars, 0, index - 1)
Console.WriteLine("Decoded string: ")
Console.WriteLine(decodedString)
End Sub
End Module
' The example displays the following output:
' String to Encode: This is the first sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
' 6E 74 65 6E 63 65 2E 20
'
' String to Encode: This is the second sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 73 65 63 6F 6E 64 20 73
' 65 6E 74 65 6E 63 65 2E 20
'
' String to Encode: This is the third sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 74 68 69 72 64 20 73 65
' 6E 74 65 6E 63 65 2E 20
'
' Decoded string:
' This is the first sentence. This is the second sentence. This is the third sentence.
Egy osztály Encoding kódolási és dekódolási módszerei úgy vannak kialakítva, hogy teljes adatkészleten működjenek; vagyis a kódolni vagy dekódolni kívánt összes adatot egyetlen metódushívásban kell megadni. Bizonyos esetekben azonban az adatok elérhetők egy streamben, és a kódolni vagy dekódolni kívánt adatok csak külön olvasási műveletekből érhetők el. Ehhez a kódolási vagy dekódolási műveletnek emlékeznie kell az előző meghívás mentett állapotára. A több metódushívásra kiterjedő kódolási és dekódolási műveletek kezelésére képes osztályok EncoderDecoder metódusai.
Egy Encoder adott kódolás objektuma a kódolás Encoding.GetEncoder tulajdonságából érhető el. Egy Decoder adott kódolás objektuma a kódolás Encoding.GetDecoder tulajdonságából érhető el. A dekódolási műveletek esetében vegye figyelembe, hogy a származtatott Decoder osztályok tartalmazzák a metódust Decoder.GetChars , de nem rendelkeznek olyan metódussal, amely megfelel a metódusnak Encoding.GetString.
Az alábbi példa bemutatja, hogy mi a különbség a Encoding.GetString Unicode-bájttömbök dekódolásának módja és Decoder.GetChars a metódusok között. A példa egy olyan sztringet kódol, amely unicode-karaktereket tartalmaz egy fájlban, majd a két dekódolási módszerrel egyszerre tíz bájtot dekódol. Mivel a helyettesítő párok a tizedik és a tizenegyedik bájtban fordulnak elő, külön metódushívásokban dekódolják. Ahogy a kimenet is mutatja, a Encoding.GetString metódus nem tudja megfelelően dekódolni a bájtokat, és ehelyett U+FFFD (REPLACE CHARACTER) karakterre cseréli őket. Ezzel szemben a Decoder.GetChars metódus sikeresen dekódolja a bájttömböt az eredeti sztring lekéréséhez.
using System;
using System.IO;
using System.Text;
public class Example
{
public static void Main()
{
// Use default replacement fallback for invalid encoding.
UnicodeEncoding enc = new UnicodeEncoding(true, false, false);
// Define a string with various Unicode characters.
string str1 = "AB YZ 19 \uD800\udc05 \u00e4";
str1 += "Unicode characters. \u00a9 \u010C s \u0062\u0308";
Console.WriteLine("Created original string...\n");
// Convert string to byte array.
byte[] bytes = enc.GetBytes(str1);
FileStream fs = File.Create(@".\characters.bin");
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes);
bw.Close();
// Read bytes from file.
FileStream fsIn = File.OpenRead(@".\characters.bin");
BinaryReader br = new BinaryReader(fsIn);
const int count = 10; // Number of bytes to read at a time.
byte[] bytesRead = new byte[10]; // Buffer (byte array).
int read; // Number of bytes actually read.
string str2 = String.Empty; // Decoded string.
// Try using Encoding object for all operations.
do {
read = br.Read(bytesRead, 0, count);
str2 += enc.GetString(bytesRead, 0, read);
} while (read == count);
br.Close();
Console.WriteLine("Decoded string using UnicodeEncoding.GetString()...");
CompareForEquality(str1, str2);
Console.WriteLine();
// Use Decoder for all operations.
fsIn = File.OpenRead(@".\characters.bin");
br = new BinaryReader(fsIn);
Decoder decoder = enc.GetDecoder();
char[] chars = new char[50];
int index = 0; // Next character to write in array.
int written = 0; // Number of chars written to array.
do {
read = br.Read(bytesRead, 0, count);
if (index + decoder.GetCharCount(bytesRead, 0, read) - 1 >= chars.Length)
Array.Resize(ref chars, chars.Length + 50);
written = decoder.GetChars(bytesRead, 0, read, chars, index);
index += written;
} while (read == count);
br.Close();
// Instantiate a string with the decoded characters.
string str3 = new String(chars, 0, index);
Console.WriteLine("Decoded string using UnicodeEncoding.Decoder.GetString()...");
CompareForEquality(str1, str3);
}
private static void CompareForEquality(string original, string decoded)
{
bool result = original.Equals(decoded);
Console.WriteLine("original = decoded: {0}",
original.Equals(decoded, StringComparison.Ordinal));
if (! result) {
Console.WriteLine("Code points in original string:");
foreach (var ch in original)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
Console.WriteLine("Code points in decoded string:");
foreach (var ch in decoded)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Created original string...
//
// Decoded string using UnicodeEncoding.GetString()...
// original = decoded: False
// Code points in original string:
// 0041 0042 0020 0059 005A 0020 0031 0039 0020 D800 DC05 0020 00E4 0055 006E 0069 0063 006F
// 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
// 0020 0073 0020 0062 0308
// Code points in decoded string:
// 0041 0042 0020 0059 005A 0020 0031 0039 0020 FFFD FFFD 0020 00E4 0055 006E 0069 0063 006F
// 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
// 0020 0073 0020 0062 0308
//
// Decoded string using UnicodeEncoding.Decoder.GetString()...
// original = decoded: True
Imports System.IO
Imports System.Text
Module Example
Public Sub Main()
' Use default replacement fallback for invalid encoding.
Dim enc As New UnicodeEncoding(True, False, False)
' Define a string with various Unicode characters.
Dim str1 As String = String.Format("AB YZ 19 {0}{1} {2}",
ChrW(&hD800), ChrW(&hDC05), ChrW(&h00e4))
str1 += String.Format("Unicode characters. {0} {1} s {2}{3}",
ChrW(&h00a9), ChrW(&h010C), ChrW(&h0062), ChrW(&h0308))
Console.WriteLine("Created original string...")
Console.WriteLine()
' Convert string to byte array.
Dim bytes() As Byte = enc.GetBytes(str1)
Dim fs As FileStream = File.Create(".\characters.bin")
Dim bw As New BinaryWriter(fs)
bw.Write(bytes)
bw.Close()
' Read bytes from file.
Dim fsIn As FileStream = File.OpenRead(".\characters.bin")
Dim br As New BinaryReader(fsIn)
Const count As Integer = 10 ' Number of bytes to read at a time.
Dim bytesRead(9) As Byte ' Buffer (byte array).
Dim read As Integer ' Number of bytes actually read.
Dim str2 As String = "" ' Decoded string.
' Try using Encoding object for all operations.
Do
read = br.Read(bytesRead, 0, count)
str2 += enc.GetString(bytesRead, 0, read)
Loop While read = count
br.Close()
Console.WriteLine("Decoded string using UnicodeEncoding.GetString()...")
CompareForEquality(str1, str2)
Console.WriteLine()
' Use Decoder for all operations.
fsIn = File.OpenRead(".\characters.bin")
br = New BinaryReader(fsIn)
Dim decoder As Decoder = enc.GetDecoder()
Dim chars(50) As Char
Dim index As Integer = 0 ' Next character to write in array.
Dim written As Integer = 0 ' Number of chars written to array.
Do
read = br.Read(bytesRead, 0, count)
If index + decoder.GetCharCount(bytesRead, 0, read) - 1 >= chars.Length Then
Array.Resize(chars, chars.Length + 50)
End If
written = decoder.GetChars(bytesRead, 0, read, chars, index)
index += written
Loop While read = count
br.Close()
' Instantiate a string with the decoded characters.
Dim str3 As New String(chars, 0, index)
Console.WriteLine("Decoded string using UnicodeEncoding.Decoder.GetString()...")
CompareForEquality(str1, str3)
End Sub
Private Sub CompareForEquality(original As String, decoded As String)
Dim result As Boolean = original.Equals(decoded)
Console.WriteLine("original = decoded: {0}",
original.Equals(decoded, StringComparison.Ordinal))
If Not result Then
Console.WriteLine("Code points in original string:")
For Each ch In original
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine("Code points in decoded string:")
For Each ch In decoded
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Created original string...
'
' Decoded string using UnicodeEncoding.GetString()...
' original = decoded: False
' Code points in original string:
' 0041 0042 0020 0059 005A 0020 0031 0039 0020 D800 DC05 0020 00E4 0055 006E 0069 0063 006F
' 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
' 0020 0073 0020 0062 0308
' Code points in decoded string:
' 0041 0042 0020 0059 005A 0020 0031 0039 0020 FFFD FFFD 0020 00E4 0055 006E 0069 0063 006F
' 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
' 0020 0073 0020 0062 0308
'
' Decoded string using UnicodeEncoding.Decoder.GetString()...
' original = decoded: True
Tartalék stratégia kiválasztása
Amikor egy metódus megpróbál kódolni vagy dekódolni egy karaktert, de nem létezik leképezés, egy tartalék stratégiát kell implementálnia, amely meghatározza a sikertelen leképezés kezelését. A tartalék stratégiáknak három típusa van:
Legjobban illeszkedő tartalék
Csere tartalék
Kivétel tartalék
Fontos
A kódolási műveletek leggyakoribb problémái akkor fordulnak elő, ha egy Unicode-karakter nem rendelhető hozzá egy adott kódlap kódolásához. A dekódolási műveletek leggyakoribb problémái akkor fordulnak elő, ha érvénytelen bájtsorozatok nem fordíthatók le érvényes Unicode-karakterekre. Ezen okokból tudnia kell, hogy melyik tartalék stratégiát használja egy adott kódolási objektum. Amikor csak lehetséges, meg kell adnia a kódolási objektum által használt tartalék stratégiát az objektum példányosításakor.
Best-Fit Fallback
Ha egy karakternek nincs pontos egyezése a célkódolásban, a kódoló megpróbálhatja leképezni egy hasonló karakterre. (A legjobban illeszkedő tartalék többnyire kódolás, nem pedig dekódolási probléma. Nagyon kevés olyan kódlap van, amely olyan karaktereket tartalmaz, amelyek nem képezhetők le sikeresen a Unicode-ra.) A legjobban illeszkedő tartalék a kódlap és a kétbájtos karakterkészlet kódolásának alapértelmezett értéke, amelyet a rendszer lekéri és Encoding.GetEncoding(Int32)Encoding.GetEncoding(String) túlterhel.
Feljegyzés
Elméletileg a .NET-ben (UTF8EncodingUnicodeEncodingés UTF32Encoding) megadott Unicode kódolási osztályok minden karakterkészletben támogatják az összes karaktert, így a legjobban illeszkedő tartalék problémák kiküszöbölésére használhatók.
A legjobban illeszkedő stratégiák a különböző kódlapok esetében eltérőek. Egyes kódlapok esetében például a teljes szélességű latin karakterek a gyakoribb félszélességű latin karakterekre vannak leképezve. Más kódlapok esetében ez a leképezés nem történik meg. Még egy agresszív, legjobban illeszkedő stratégia esetén sem képzelhető el néhány karakter egyes kódolásokban. Egy kínai ideográfiának például nincs ésszerű leképezése az 1252-s kódlapra. Ebben az esetben a rendszer egy helyettesítő sztringet használ. Alapértelmezés szerint ez a sztring csak egyetlen KÉRDŐJEL (U+003F).
Feljegyzés
A legjobban illeszkedő stratégiák nincsenek részletesen dokumentálva. A Unicode Consortium webhelyén azonban több kódlap is dokumentálva van. Tekintse át a mappában található readme.txt fájlt a leképezési fájlok értelmezésének leírásához.
Az alábbi példa az 1252-s kódlapot (a nyugat-európai nyelvek Windows kódlapját) használja a legjobban illeszkedő leképezés és hátrányai szemléltetésére. A Encoding.GetEncoding(Int32) metódus egy kódolási objektum lekérésére szolgál az 1252-s kódlaphoz. Alapértelmezés szerint a Unicode-karakterek legjobban illeszkedő leképezését használja, amelyet nem támogat. A példa létrehoz egy sztringet, amely három nem ASCII karaktert tartalmaz – A KÖR ALAKÚ LATIN NAGYBETŰS S (U+24C8), a FELSŐ INDEX ÖT (U+2075) és az INFINITY (U+221E) karaktert szóközökkel elválasztva. Ahogy a példa kimenete is mutatja, a sztring kódolásakor a három eredeti nem szóköz karakter helyébe a KÉRDŐJEL (U+003F), az ÖT SZÁMJEGY (U+0035) és a NYOLCADIK SZÁMJEGY (U+0038) lép. A NYOLCADIK SZÁMJEGY különösen gyenge helyettesítője a nem támogatott INFINITY karakternek, a KÉRDŐJEL pedig azt jelzi, hogy az eredeti karakterhez nem állt rendelkezésre leképezés.
using System;
using System.Text;
public class Example
{
public static void Main()
{
// Get an encoding for code page 1252 (Western Europe character set).
Encoding cp1252 = Encoding.GetEncoding(1252);
// Define and display a string.
string str = "\u24c8 \u2075 \u221e";
Console.WriteLine("Original string: " + str);
Console.Write("Code points in string: ");
foreach (var ch in str)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine("\n");
// Encode a Unicode string.
Byte[] bytes = cp1252.GetBytes(str);
Console.Write("Encoded bytes: ");
foreach (byte byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");
// Decode the string.
string str2 = cp1252.GetString(bytes);
Console.WriteLine("String round-tripped: {0}", str.Equals(str2));
if (! str.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
}
}
}
// The example displays the following output:
// Original string: Ⓢ ⁵ ∞
// Code points in string: 24C8 0020 2075 0020 221E
//
// Encoded bytes: 3F 20 35 20 38
//
// String round-tripped: False
// ? 5 8
// 003F 0020 0035 0020 0038
Imports System.Text
Module Example
Public Sub Main()
' Get an encoding for code page 1252 (Western Europe character set).
Dim cp1252 As Encoding = Encoding.GetEncoding(1252)
' Define and display a string.
Dim str As String = String.Format("{0} {1} {2}", ChrW(&h24c8), ChrW(&H2075), ChrW(&h221E))
Console.WriteLine("Original string: " + str)
Console.Write("Code points in string: ")
For Each ch In str
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()
' Encode a Unicode string.
Dim bytes() As Byte = cp1252.GetBytes(str)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()
' Decode the string.
Dim str2 As String = cp1252.GetString(bytes)
Console.WriteLine("String round-tripped: {0}", str.Equals(str2))
If Not str.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
End If
End Sub
End Module
' The example displays the following output:
' Original string: Ⓢ ⁵ ∞
' Code points in string: 24C8 0020 2075 0020 221E
'
' Encoded bytes: 3F 20 35 20 38
'
' String round-tripped: False
' ? 5 8
' 003F 0020 0035 0020 0038
A legjobban illeszkedő leképezés egy olyan objektum alapértelmezett viselkedése Encoding , amely Unicode-adatokat kódlapadatokba kódol, és vannak régi alkalmazások, amelyek erre a viselkedésre támaszkodnak. A legtöbb új alkalmazásnak azonban biztonsági okokból kerülnie kell a legjobban illeszkedő viselkedést. Az alkalmazások például nem helyezhetnek el tartománynevet a legjobban illeszkedő kódolással.
Feljegyzés
A kódoláshoz egyéni, legjobban illeszkedő tartalék leképezést is implementálhat. További információkért lásd az Egyéni tartalék stratégia implementálását ismertető szakaszt.
Ha a legjobban illeszkedő tartalék az alapértelmezett kódolási objektum, másik tartalék stratégiát is választhat, amikor lekéri az objektumot Encoding a túlterhelés vagy Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) a Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) túlterhelés meghívásával. Az alábbi szakasz egy példát tartalmaz, amely az 1252-es kódlapra nem leképezhető karaktereket csillaggal (*) helyettesíti.
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding cp1252r = Encoding.GetEncoding(1252,
new EncoderReplacementFallback("*"),
new DecoderReplacementFallback("*"));
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
byte[] bytes = cp1252r.GetBytes(str1);
string str2 = cp1252r.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
// Round-trip: False
// * * *
// 002A 0020 002A 0020 002A
Imports System.Text
Module Example
Public Sub Main()
Dim cp1252r As Encoding = Encoding.GetEncoding(1252,
New EncoderReplacementFallback("*"),
New DecoderReplacementFallback("*"))
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Dim bytes() As Byte = cp1252r.GetBytes(str1)
Dim str2 As String = cp1252r.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
' Round-trip: False
' * * *
' 002A 0020 002A 0020 002A
Csere tartalék
Ha egy karakternek nincs pontos egyezése a célsémában, de nincs megfelelő karakter, amelyet le lehet képezni, az alkalmazás megadhat egy helyettesítő karaktert vagy sztringet. Ez a Unicode-dekódoló alapértelmezett viselkedése, amely felülírja azokat a két bájtos sorozatokat, amelyeket nem tud dekódolni REPLACEMENT_CHARACTER (U+FFFD). Ez az osztály alapértelmezett viselkedése ASCIIEncoding is, amely minden olyan karaktert lecserél, amelyet nem tud kódolni vagy dekódolni kérdőjellel. Az alábbi példa az előző példában szereplő Unicode-sztring karaktercseréit szemlélteti. Ahogy a kimenet is mutatja, minden olyan karaktert, amelyet nem lehet ASCII bájtértékké dekódolni, 0x3F váltja fel, amely egy kérdőjel ASCII-kódja.
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding enc = Encoding.ASCII;
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine("\n");
// Encode the original string using the ASCII encoder.
byte[] bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");
// Decode the ASCII bytes.
string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
//
// Encoded bytes: 3F 20 3F 20 3F
//
// Round-trip: False
// ? ? ?
// 003F 0020 003F 0020 003F
Imports System.Text
Module Example
Public Sub Main()
Dim enc As Encoding = Encoding.Ascii
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()
' Encode the original string using the ASCII encoder.
Dim bytes() As Byte = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()
' Decode the ASCII bytes.
Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
'
' Encoded bytes: 3F 20 3F 20 3F
'
' Round-trip: False
' ? ? ?
' 003F 0020 003F 0020 003F
A .NET tartalmazza azokat az EncoderReplacementFallback osztályokat, DecoderReplacementFallback amelyek helyettesítő sztringet helyettesítenek, ha egy karakter nem felel meg pontosan egy kódolási vagy dekódolási műveletnek. Alapértelmezés szerint ez a helyettesítő sztring kérdőjel, de egy osztálykonstruktor túlterhelését is meghívhatja egy másik sztring kiválasztásához. A helyettesítő sztring általában egyetlen karakter, bár ez nem követelmény. Az alábbi példa egy csillagot (*) helyettesítő sztringet használó objektum példányosításával EncoderReplacementFallback módosítja az 1252 kódoló kódolójának viselkedését.
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding cp1252r = Encoding.GetEncoding(1252,
new EncoderReplacementFallback("*"),
new DecoderReplacementFallback("*"));
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
byte[] bytes = cp1252r.GetBytes(str1);
string str2 = cp1252r.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
// Round-trip: False
// * * *
// 002A 0020 002A 0020 002A
Imports System.Text
Module Example
Public Sub Main()
Dim cp1252r As Encoding = Encoding.GetEncoding(1252,
New EncoderReplacementFallback("*"),
New DecoderReplacementFallback("*"))
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Dim bytes() As Byte = cp1252r.GetBytes(str1)
Dim str2 As String = cp1252r.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
' Round-trip: False
' * * *
' 002A 0020 002A 0020 002A
Feljegyzés
A kódoláshoz helyettesítő osztályt is implementálhat. További információkért lásd az Egyéni tartalék stratégia implementálását ismertető szakaszt.
A KÉRDŐJEL (U+003F) mellett a Unicode HELYETTESÍTŐ KARAKTERt (U+FFFD) gyakran használják helyettesítő sztringként, különösen akkor, ha olyan bájtsorozatokat dekódol, amelyek nem fordíthatók le Unicode-karakterekre. A helyettesítő sztringek azonban szabadon választhatók, és több karaktert is tartalmazhatnak.
Kivétel tartalék
Ahelyett, hogy a legjobban illeszkedő tartalékot vagy helyettesítő sztringet biztosítanának, a kódoló képes egy EncoderFallbackException karakterkészlet kódolására, és a dekódoló képes DecoderFallbackException a bájttömbök dekódolására. Ha kivételt szeretne tenni a kódolási és dekódolási műveletekben, adjon meg egy EncoderExceptionFallback objektumot és egy DecoderExceptionFallback objektumot a Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) metódusnak. Az alábbi példa az osztály kivétel-tartalékait ASCIIEncoding mutatja be.
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding enc = Encoding.GetEncoding("us-ascii",
new EncoderExceptionFallback(),
new DecoderExceptionFallback());
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine("\n");
// Encode the original string using the ASCII encoder.
byte[] bytes = {};
try {
bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine();
}
catch (EncoderFallbackException e) {
Console.Write("Exception: ");
if (e.IsUnknownSurrogate())
Console.WriteLine("Unable to encode surrogate pair 0x{0:X4} 0x{1:X3} at index {2}.",
Convert.ToUInt16(e.CharUnknownHigh),
Convert.ToUInt16(e.CharUnknownLow),
e.Index);
else
Console.WriteLine("Unable to encode 0x{0:X4} at index {1}.",
Convert.ToUInt16(e.CharUnknown),
e.Index);
return;
}
Console.WriteLine();
// Decode the ASCII bytes.
try {
string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
catch (DecoderFallbackException e) {
Console.Write("Unable to decode byte(s) ");
foreach (byte unknown in e.BytesUnknown)
Console.Write("0x{0:X2} ");
Console.WriteLine("at index {0}", e.Index);
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
//
// Exception: Unable to encode 0x24C8 at index 0.
Imports System.Text
Module Example
Public Sub Main()
Dim enc As Encoding = Encoding.GetEncoding("us-ascii",
New EncoderExceptionFallback(),
New DecoderExceptionFallback())
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()
' Encode the original string using the ASCII encoder.
Dim bytes() As Byte = {}
Try
bytes = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Catch e As EncoderFallbackException
Console.Write("Exception: ")
If e.IsUnknownSurrogate() Then
Console.WriteLine("Unable to encode surrogate pair 0x{0:X4} 0x{1:X3} at index {2}.",
Convert.ToUInt16(e.CharUnknownHigh),
Convert.ToUInt16(e.CharUnknownLow),
e.Index)
Else
Console.WriteLine("Unable to encode 0x{0:X4} at index {1}.",
Convert.ToUInt16(e.CharUnknown),
e.Index)
End If
Exit Sub
End Try
Console.WriteLine()
' Decode the ASCII bytes.
Try
Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
Catch e As DecoderFallbackException
Console.Write("Unable to decode byte(s) ")
For Each unknown As Byte In e.BytesUnknown
Console.Write("0x{0:X2} ")
Next
Console.WriteLine("at index {0}", e.Index)
End Try
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
'
' Exception: Unable to encode 0x24C8 at index 0.
Feljegyzés
A kódolási művelethez egyéni kivételkezelőt is implementálhat. További információkért lásd az Egyéni tartalék stratégia implementálását ismertető szakaszt.
Az EncoderFallbackException és DecoderFallbackException az objektumok a következő információkat adják meg a kivételt okozó feltételről:
Az EncoderFallbackException objektum tartalmaz egy metódust IsUnknownSurrogate , amely azt jelzi, hogy a kódolható karakter vagy karakterek ismeretlen helyettesítő párt képviselnek (ebben az esetben a metódus visszaadja
true
) vagy egy ismeretlen egy karaktert (ebben az esetben a metódus visszaadjafalse
). A helyettesítő párban szereplő karakterek a tulajdonságokból és EncoderFallbackException.CharUnknownLow a EncoderFallbackException.CharUnknownHigh tulajdonságokból érhetők el. Az ismeretlen egy karakter elérhető a EncoderFallbackException.CharUnknown tulajdonságból. A EncoderFallbackException.Index tulajdonság azt a pozíciót jelzi a sztringben, ahol az első nem kódolható karakter található.Az DecoderFallbackException objektum tartalmaz egy tulajdonságot BytesUnknown , amely bájtok tömböt ad vissza, amely nem dekódolható. A DecoderFallbackException.Index tulajdonság az ismeretlen bájtok kezdő pozícióját jelzi.
Bár az és DecoderFallbackException az EncoderFallbackException objektumok megfelelő diagnosztikai információkat nyújtanak a kivételről, nem biztosítanak hozzáférést a kódolási vagy dekódolási pufferhez. Ezért nem teszik lehetővé az érvénytelen adatok cseréjét vagy kijavítását a kódolási vagy dekódolási módszeren belül.
Egyéni tartalék stratégia megvalósítása
A kódlapok által belsőleg implementált legjobban illeszkedő leképezés mellett a .NET a következő osztályokat is tartalmazza a tartalék stratégia implementálásához:
Karakterek használata EncoderReplacementFallback és EncoderReplacementFallbackBuffer cseréje kódolási műveletekben.
Karakterek használata DecoderReplacementFallback és DecoderReplacementFallbackBuffer cseréje a dekódolási műveletekben.
Használjon EncoderExceptionFallback és EncoderExceptionFallbackBuffer dobjon egy EncoderFallbackException olyan karaktert, amely nem kódolható.
Használjon DecoderExceptionFallback és DecoderExceptionFallbackBuffer dobjon egy DecoderFallbackException olyan karaktert, amelyet nem lehet dekódolni.
Emellett az alábbi lépések végrehajtásával implementálhat egy egyéni megoldást, amely a legjobban illeszkedő tartalékot, csere-tartalékot vagy kivétel-tartalékot használja:
Osztályt EncoderFallback a kódolási műveletekből és a dekódolási műveletekből DecoderFallback származtat.
Osztályt EncoderFallbackBuffer a kódolási műveletekből és a dekódolási műveletekből DecoderFallbackBuffer származtat.
Kivétel-tartalék esetén, ha az előre definiált EncoderFallbackException és DecoderFallbackException az osztályok nem felelnek meg az igényeinek, egy osztályt egy kivételobjektumból, például Exception vagy ArgumentException.
Az EncoderFallback vagy a DecoderFallback származtatása
Egyéni tartalékmegoldás implementálásához létre kell hoznia egy osztályt, amely a kódolási EncoderFallback műveletekhez és DecoderFallback a dekódolási műveletekhez öröklődik. Ezeknek az osztályoknak a példányait a rendszer átadja a Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) metódusnak, és közvetítőként szolgál a kódolási osztály és a tartalék megvalósítás között.
Ha egyéni tartalék megoldást hoz létre kódolóhoz vagy dekóderhez, a következő tagokat kell implementálnia:
Az EncoderFallback.MaxCharCount a vagy DecoderFallback.MaxCharCount tulajdonság, amely a lehető legtöbb karaktert adja vissza, amelyet a legjobban illeszkedő, helyettesítő vagy kivétel tartalék képes visszaadni egyetlen karakter helyére. Egyéni kivétel tartalék esetén az értéke nulla.
Az EncoderFallback.CreateFallbackBuffer egyéni EncoderFallbackBuffer vagy implementációt visszaadó metódus DecoderFallback.CreateFallbackBuffer vagy DecoderFallbackBuffer metódus. A metódust a kódoló hívja meg, amikor az első karakterrel találkozik, amelyet nem tud sikeresen kódolni, vagy a dekódoló, amikor az első bájttal találkozik, amelyet nem tud sikeresen dekódolni.
Az EncoderFallbackBuffer vagy a DecoderFallbackBuffer származtatása
Egyéni tartalékmegoldás implementálásához létre kell hoznia egy olyan osztályt is, amely a kódolási műveletekhez és DecoderFallbackBuffer a dekódolási műveletekhez öröklődikEncoderFallbackBuffer. Ezeknek az osztályoknak a példányait az CreateFallbackBuffer osztályok metódusa EncoderFallbackDecoderFallback adja vissza. A EncoderFallback.CreateFallbackBuffer metódust a kódoló hívja meg, amikor az első karaktert nem tudja kódolni, és a DecoderFallback.CreateFallbackBuffer metódust a dekódoló hívja meg, amikor egy vagy több bájttal találkozik, amelyet nem tud dekódolni. Az EncoderFallbackBuffer és DecoderFallbackBuffer az osztályok biztosítják a tartalék megvalósítást. Minden példány egy puffert jelöl, amely tartalmazza a tartalék karaktereket, amelyek lecserélik a nem kódolható karaktert vagy a nem dekódolható bájtsorozatot.
Ha egyéni tartalék megoldást hoz létre kódolóhoz vagy dekóderhez, a következő tagokat kell implementálnia:
A EncoderFallbackBuffer.Fallback vagy DecoderFallbackBuffer.Fallback metódus. EncoderFallbackBuffer.Fallback a kódoló meghívja, hogy a tartalék puffernek adja meg a kódolható karakterre vonatkozó információkat. Mivel a kódolandó karakter lehet helyettesítő pár, ez a módszer túlterhelt. A rendszer egy túlterhelést ad át a kódolandó karakternek és a sztring indexének. A második túlterhelés a magas és alacsony helyettes, valamint az index a sztringben. A DecoderFallbackBuffer.Fallback metódust a dekóder hívja meg, hogy a tartalék puffer olyan információkat adjon meg a bájtokról, amelyeket nem tud dekódolni. Ez a metódus egy bájttömböt ad át, amelyet nem tud dekódolni, valamint az első bájt indexét. A tartalék metódusnak akkor kell visszaadnia
true
, ha a tartalék puffer a legjobban illeszkedő vagy helyettesítő karaktert vagy karaktereket tud adni, ellenkező esetben a függvénynek vissza kell adniafalse
. Kivétel-visszavétel esetén a tartalék metódusnak kivételt kell eredményeznie.A EncoderFallbackBuffer.GetNextChar kódoló vagy dekóder által ismétlődően meghívott vagy DecoderFallbackBuffer.GetNextChar metódus, amely a tartalék pufferből kéri le a következő karaktert. Az összes tartalék karakter visszaadásakor a metódusnak U+0000 értéket kell visszaadnia.
Az EncoderFallbackBuffer.Remaining a vagy DecoderFallbackBuffer.Remaining tulajdonság, amely a tartalék pufferben fennmaradó karakterek számát adja vissza.
Az EncoderFallbackBuffer.MovePrevious a vagy DecoderFallbackBuffer.MovePrevious metódus, amely a tartalék puffer aktuális pozícióját az előző karakterre helyezi át.
Az EncoderFallbackBuffer.Reset a vagy DecoderFallbackBuffer.Reset metódus, amely újraincializálja a tartalék puffert.
Ha a tartalék megvalósítás a legjobban illeszkedő tartalék vagy csere tartalék, akkor az osztályok két privát példánymezőből EncoderFallbackBuffer származnak és DecoderFallbackBuffer tartanak fenn: a pufferben lévő karakterek pontos számát, valamint a puffer következő karakterének indexét a visszatéréshez.
Példa EncoderFallbackre
Egy korábbi példa helyettesítő tartalékot használt az ASCII-karaktereknek nem megfelelő Unicode-karakterek csillaggal (*) való helyettesítésére. Az alábbi példa egy egyéni, legjobban illeszkedő tartalék implementációt használ a nem ASCII-karakterek jobb leképezéséhez.
Az alábbi kód egy olyan osztályt CustomMapper
határoz meg, amely a EncoderFallback nem ASCII-karakterek legjobban illeszkedő leképezésének kezeléséhez származik. A CreateFallbackBuffer
metódus egy CustomMapperFallbackBuffer
objektumot ad vissza, amely biztosítja a megvalósítást EncoderFallbackBuffer . Az CustomMapper
osztály objektummal Dictionary<TKey,TValue> tárolja a nem támogatott Unicode-karakterek (a kulcsérték) és a hozzájuk tartozó 8 bites karakterek leképezését (amelyeket két egymást követő bájtban tárol egy 64 bites egész számban). Ha elérhetővé szeretné tenni ezt a leképezést a tartalék puffer számára, a CustomMapper
példány paraméterként lesz átadva az CustomMapperFallbackBuffer
osztálykonstruktornak. Mivel a leghosszabb leképezés az U+221E Unicode karakter "INF" sztringje, a MaxCharCount
tulajdonság 3 értéket ad vissza.
public class CustomMapper : EncoderFallback
{
public string DefaultString;
internal Dictionary<ushort, ulong> mapping;
public CustomMapper() : this("*")
{
}
public CustomMapper(string defaultString)
{
this.DefaultString = defaultString;
// Create table of mappings
mapping = new Dictionary<ushort, ulong>();
mapping.Add(0x24C8, 0x53);
mapping.Add(0x2075, 0x35);
mapping.Add(0x221E, 0x49004E0046);
}
public override EncoderFallbackBuffer CreateFallbackBuffer()
{
return new CustomMapperFallbackBuffer(this);
}
public override int MaxCharCount
{
get { return 3; }
}
}
Public Class CustomMapper : Inherits EncoderFallback
Public DefaultString As String
Friend mapping As Dictionary(Of UShort, ULong)
Public Sub New()
Me.New("?")
End Sub
Public Sub New(ByVal defaultString As String)
Me.DefaultString = defaultString
' Create table of mappings
mapping = New Dictionary(Of UShort, ULong)
mapping.Add(&H24C8, &H53)
mapping.Add(&H2075, &H35)
mapping.Add(&H221E, &H49004E0046)
End Sub
Public Overrides Function CreateFallbackBuffer() As System.Text.EncoderFallbackBuffer
Return New CustomMapperFallbackBuffer(Me)
End Function
Public Overrides ReadOnly Property MaxCharCount As Integer
Get
Return 3
End Get
End Property
End Class
Az alábbi kód határozza meg az CustomMapperFallbackBuffer
osztályt, amely a következőből EncoderFallbackBufferszármazik: A példányban CustomMapper
definiált, legjobban illeszkedő leképezéseket tartalmazó szótár az osztálykonstruktorából érhető el. A Fallback
metódus akkor ad vissza true
, ha az ASCII kódoló által nem kódolható Unicode-karakterek bármelyike definiálva van a leképezési szótárban, ellenkező esetben ad vissza false
. Minden tartalék esetében a privát count
változó a visszaadandó karakterek számát jelzi, a privát index
változó pedig a következő visszaadandó karakter karakterláncpufferének charsToReturn
pozícióját jelzi.
public class CustomMapperFallbackBuffer : EncoderFallbackBuffer
{
int count = -1; // Number of characters to return
int index = -1; // Index of character to return
CustomMapper fb;
string charsToReturn;
public CustomMapperFallbackBuffer(CustomMapper fallback)
{
this.fb = fallback;
}
public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
{
// Do not try to map surrogates to ASCII.
return false;
}
public override bool Fallback(char charUnknown, int index)
{
// Return false if there are already characters to map.
if (count >= 1) return false;
// Determine number of characters to return.
charsToReturn = String.Empty;
ushort key = Convert.ToUInt16(charUnknown);
if (fb.mapping.ContainsKey(key)) {
byte[] bytes = BitConverter.GetBytes(fb.mapping[key]);
int ctr = 0;
foreach (var byt in bytes) {
if (byt > 0) {
ctr++;
charsToReturn += (char) byt;
}
}
count = ctr;
}
else {
// Return default.
charsToReturn = fb.DefaultString;
count = 1;
}
this.index = charsToReturn.Length - 1;
return true;
}
public override char GetNextChar()
{
// We'll return a character if possible, so subtract from the count of chars to return.
count--;
// If count is less than zero, we've returned all characters.
if (count < 0)
return '\u0000';
this.index--;
return charsToReturn[this.index + 1];
}
public override bool MovePrevious()
{
// Original: if count >= -1 and pos >= 0
if (count >= -1) {
count++;
return true;
}
else {
return false;
}
}
public override int Remaining
{
get { return count < 0 ? 0 : count; }
}
public override void Reset()
{
count = -1;
index = -1;
}
}
Public Class CustomMapperFallbackBuffer : Inherits EncoderFallbackBuffer
Dim count As Integer = -1 ' Number of characters to return
Dim index As Integer = -1 ' Index of character to return
Dim fb As CustomMapper
Dim charsToReturn As String
Public Sub New(ByVal fallback As CustomMapper)
MyBase.New()
Me.fb = fallback
End Sub
Public Overloads Overrides Function Fallback(ByVal charUnknownHigh As Char, ByVal charUnknownLow As Char, ByVal index As Integer) As Boolean
' Do not try to map surrogates to ASCII.
Return False
End Function
Public Overloads Overrides Function Fallback(ByVal charUnknown As Char, ByVal index As Integer) As Boolean
' Return false if there are already characters to map.
If count >= 1 Then Return False
' Determine number of characters to return.
charsToReturn = String.Empty
Dim key As UShort = Convert.ToUInt16(charUnknown)
If fb.mapping.ContainsKey(key) Then
Dim bytes() As Byte = BitConverter.GetBytes(fb.mapping.Item(key))
Dim ctr As Integer
For Each byt In bytes
If byt > 0 Then
ctr += 1
charsToReturn += Chr(byt)
End If
Next
count = ctr
Else
' Return default.
charsToReturn = fb.DefaultString
count = 1
End If
Me.index = charsToReturn.Length - 1
Return True
End Function
Public Overrides Function GetNextChar() As Char
' We'll return a character if possible, so subtract from the count of chars to return.
count -= 1
' If count is less than zero, we've returned all characters.
If count < 0 Then Return ChrW(0)
Me.index -= 1
Return charsToReturn(Me.index + 1)
End Function
Public Overrides Function MovePrevious() As Boolean
' Original: if count >= -1 and pos >= 0
If count >= -1 Then
count += 1
Return True
Else
Return False
End If
End Function
Public Overrides ReadOnly Property Remaining As Integer
Get
Return If(count < 0, 0, count)
End Get
End Property
Public Overrides Sub Reset()
count = -1
index = -1
End Sub
End Class
Az alábbi kód ezután példányosítja az CustomMapper
objektumot, és átadja annak egy példányát a Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) metódusnak. A kimenet azt jelzi, hogy a legjobban illeszkedő tartalék implementáció sikeresen kezeli az eredeti sztring három nem ASCII karakterét.
using System;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main()
{
Encoding enc = Encoding.GetEncoding("us-ascii", new CustomMapper(), new DecoderExceptionFallback());
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
for (int ctr = 0; ctr <= str1.Length - 1; ctr++) {
Console.Write("{0} ", Convert.ToUInt16(str1[ctr]).ToString("X4"));
if (ctr == str1.Length - 1)
Console.WriteLine();
}
Console.WriteLine();
// Encode the original string using the ASCII encoder.
byte[] bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");
// Decode the ASCII bytes.
string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
Imports System.Text
Imports System.Collections.Generic
Module Module1
Sub Main()
Dim enc As Encoding = Encoding.GetEncoding("us-ascii", New CustomMapper(), New DecoderExceptionFallback())
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&H24C8), ChrW(&H2075), ChrW(&H221E))
Console.WriteLine(str1)
For ctr As Integer = 0 To str1.Length - 1
Console.Write("{0} ", Convert.ToUInt16(str1(ctr)).ToString("X4"))
If ctr = str1.Length - 1 Then Console.WriteLine()
Next
Console.WriteLine()
' Encode the original string using the ASCII encoder.
Dim bytes() As Byte = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()
' Decode the ASCII bytes.
Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module