Megosztás a következőn keresztül:


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+0000U+007Ftá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:

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:

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:

  1. Osztályt EncoderFallback a kódolási műveletekből és a dekódolási műveletekből DecoderFallback származtat.

  2. Osztályt EncoderFallbackBuffer a kódolási műveletekből és a dekódolási műveletekből DecoderFallbackBuffer származtat.

  3. 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 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:

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 charsToReturnpozí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

Lásd még