Delen via


Tekencoderingsklassen gebruiken in .NET

In dit artikel wordt uitgelegd hoe u de klassen gebruikt die .NET biedt voor het coderen en decoderen van tekst met behulp van verschillende coderingsschema's. In de instructies wordt ervan uitgegaan dat u Inleiding tot tekencodering in .NET hebt gelezen.

Encoders en decoders

.NET biedt coderingsklassen waarmee tekst wordt gecodeerd en gedecodeerd met behulp van verschillende coderingssystemen. De klasse beschrijft bijvoorbeeld UTF8Encoding de regels voor codering naar en decodering van UTF-8. .NET maakt gebruik van UTF-16-codering (vertegenwoordigd door de UnicodeEncoding klasse) voor string exemplaren. Encoders en decoders zijn beschikbaar voor andere coderingsschema's.

Codering en decodering kunnen ook validatie bevatten. De klasse controleert bijvoorbeeld UnicodeEncoding alle char exemplaren in het surrogaatbereik om ervoor te zorgen dat deze zich in geldige surrogaatparen bevindt. Een terugvalstrategie bepaalt hoe een encoder ongeldige tekens verwerkt of hoe een decoder ongeldige bytes verwerkt.

Waarschuwing

.NET-coderingsklassen bieden een manier om tekengegevens op te slaan en te converteren. Ze mogen niet worden gebruikt voor het opslaan van binaire gegevens in tekenreeksvorm. Afhankelijk van de gebruikte codering kan het converteren van binaire gegevens naar tekenreeksindeling met de coderingsklassen onverwacht gedrag veroorzaken en onjuiste of beschadigde gegevens produceren. Gebruik de Convert.ToBase64String methode om binaire gegevens te converteren naar een tekenreeksformulier.

Alle tekencoderingsklassen in .NET nemen over van de System.Text.Encoding klasse. Dit is een abstracte klasse die de functionaliteit definieert die gemeenschappelijk is voor alle tekencoderingen. Ga als volgt te werk om toegang te krijgen tot de afzonderlijke coderingsobjecten die zijn geïmplementeerd in .NET:

  • Gebruik de statische eigenschappen van de Encoding klasse, die objecten retourneren die de standaardtekencoderingen vertegenwoordigen die beschikbaar zijn in .NET (ASCII, UTF-7, UTF-8, UTF-16 en UTF-32). De eigenschap retourneert bijvoorbeeld Encoding.Unicode een UnicodeEncoding object. Elk object maakt gebruik van vervangende terugval om tekenreeksen te verwerken die niet kunnen worden gecodeerd en bytes die het niet kan decoderen. Zie Vervangende terugval voor meer informatie.

  • Roep de klasseconstructor van de codering aan. Objecten voor de ASCII-, UTF-7-, UTF-8-, UTF-16- en UTF-32-coderingen kunnen op deze manier worden geïnstantieerd. Standaard gebruikt elk object vervangende terugval om tekenreeksen te verwerken die het niet kan coderen en bytes die het niet kan decoderen, maar u kunt opgeven dat er in plaats daarvan een uitzondering moet worden gegenereerd. Zie Vervangende terugval en Uitzonderingsback voor meer informatie.

  • Roep de Encoding(Int32) constructor aan en geef dit een geheel getal door dat de codering vertegenwoordigt. Standaardcoderingsobjecten maken gebruik van vervangende terugval en codepagina en DBCS-coderingsobjecten (Double-Byte Character Set) maken gebruik van de best passende terugval om tekenreeksen te verwerken die ze niet kunnen coderen en bytes die ze niet kunnen decoderen. Zie Best-fit fallback voor meer informatie.

  • Roep de Encoding.GetEncoding methode aan, die elke standaard-, codepagina of DBCS-codering retourneert die beschikbaar is in .NET. Met overbelastingen kunt u een terugvalobject opgeven voor zowel de encoder als de decoder.

U kunt informatie ophalen over alle coderingen die beschikbaar zijn in .NET door de methode aan te Encoding.GetEncodings roepen. .NET ondersteunt de tekencoderingsschema's die worden vermeld in de volgende tabel.

Coderingsklasse Beschrijving
ASCII Codeert een beperkt aantal tekens met behulp van de onderste zeven bits van een byte. Omdat deze codering alleen tekenwaarden van U+0000 via U+007Fondersteunt, is het in de meeste gevallen ontoereikend voor geinternationaliseerde toepassingen.
UTF-7 Vertegenwoordigt tekens als reeksen van 7-bits ASCII-tekens. Niet-ASCII Unicode-tekens worden vertegenwoordigd door een escape-reeks ASCII-tekens. UTF-7 ondersteunt protocollen zoals e-mail en nieuwsgroep. UTF-7 is echter niet bijzonder veilig of robuust. In sommige gevallen kan het wijzigen van één bit de interpretatie van een hele UTF-7-tekenreeks ingrijpend wijzigen. In andere gevallen kunnen verschillende UTF-7-tekenreeksen dezelfde tekst coderen. Voor reeksen met niet-ASCII-tekens vereist UTF-7 meer ruimte dan UTF-8 en is codering/decodering langzamer. Daarom moet u UTF-8 gebruiken in plaats van UTF-7, indien mogelijk.
UTF-8 Vertegenwoordigt elk Unicode-codepunt als een reeks van één tot vier bytes. UTF-8 ondersteunt 8-bits gegevensgrootten en werkt goed met veel bestaande besturingssystemen. Voor het ASCII-bereik van tekens is UTF-8 identiek aan ASCII-codering en is een bredere set tekens toegestaan. Voor CJK-scripts (Chinees-Japans-Koreaans) kan UTF-8 echter drie bytes voor elk teken vereisen en kunnen grotere gegevensgrootten dan UTF-16 veroorzaken. Soms rechtvaardigt de hoeveelheid ASCII-gegevens, zoals HTML-tags, de toegenomen grootte voor het CJK-bereik.
UTF-16 Vertegenwoordigt elk Unicode-codepunt als een reeks van één of twee 16-bits gehele getallen. Voor de meest voorkomende Unicode-tekens is slechts één UTF-16-codepunt vereist, hoewel aanvullende Unicode-tekens (U+10000 en hoger) twee UTF-16-surrogaatcodepunten vereisen. Zowel little-endian als big-endian byte orders worden ondersteund. UTF-16-codering wordt gebruikt door de algemene taalruntime voor representatie Char en String waarden, en wordt gebruikt door het Windows-besturingssysteem om waarden weer te geven WCHAR .
UTF-32 Vertegenwoordigt elk Unicode-codepunt als een 32-bits geheel getal. Zowel little-endian als big-endian byte orders worden ondersteund. UTF-32-codering wordt gebruikt wanneer toepassingen het gedrag van het surrogaatcodepunt van UTF-16-codering op besturingssystemen waarvoor gecodeerde ruimte te belangrijk is. Eén glyph die op een display wordt weergegeven, kan nog steeds worden gecodeerd met meer dan één UTF-32-teken.
ANSI/ISO-codering Biedt ondersteuning voor verschillende codepagina's. Op Windows-besturingssystemen worden codepagina's gebruikt ter ondersteuning van een specifieke taal of groep talen. Zie de Encoding klasse voor een tabel met de codepagina's die door .NET worden ondersteund. U kunt een coderingsobject voor een bepaalde codepagina ophalen door de methode aan te Encoding.GetEncoding(Int32) roepen. Een codepagina bevat 256 codepunten en is gebaseerd op nul. In de meeste codepagina's vertegenwoordigen codepunten 0 tot en met 127 de ASCII-tekenset en verschillen codepunten 128 tot en met 255 aanzienlijk tussen codepagina's. Codepagina 1252 bevat bijvoorbeeld de tekens voor Latijnse schrijfsystemen, waaronder Engels, Duits en Frans. De laatste 128 codepunten op codepagina 1252 bevatten de accenttekens. Codepagina 1253 bevat tekencodes die vereist zijn in het Griekse schrijfsysteem. De laatste 128 codepunten op codepagina 1253 bevatten de Griekse tekens. Als gevolg hiervan kan een toepassing die afhankelijk is van ANSI-codepagina's geen Grieks en Duits opslaan in dezelfde tekststroom, tenzij deze een id bevat die de codepagina waarnaar wordt verwezen aangeeft.
DBCS-coderingen (Double-byte Character Set) Ondersteunt talen, zoals Chinees, Japans en Koreaans, die meer dan 256 tekens bevatten. In een DBCS vertegenwoordigt een paar codepunten (een dubbele byte) elk teken. De Encoding.IsSingleByte eigenschap retourneert false voor DBCS-coderingen. U kunt een coderingsobject voor een bepaalde DBCS ophalen door de methode aan te Encoding.GetEncoding(Int32) roepen. Wanneer een toepassing DBCS-gegevens verwerkt, wordt de eerste byte van een DBCS-teken (de lead-byte) verwerkt in combinatie met de trail-byte die er direct op volgt. Omdat één paar dubbele bytecodepunten verschillende tekens kunnen vertegenwoordigen, afhankelijk van de codepagina, staat dit schema nog steeds niet toe dat twee talen, zoals Japans en Chinees, in dezelfde gegevensstroom worden gecombineerd.

Met deze coderingen kunt u werken met Unicode-tekens en met coderingen die het meest worden gebruikt in verouderde toepassingen. Daarnaast kunt u een aangepaste codering maken door een klasse te definiëren die is afgeleid van Encoding en de leden ervan overschrijft.

Ondersteuning voor .NET Core-codering

Standaard maakt .NET Core geen codetabelcoderingen beschikbaar, behalve codepagina 28591 en de Unicode-coderingen, zoals UTF-8 en UTF-16. U kunt echter de codepaginacoderingen toevoegen die zijn gevonden in standaard Windows-apps die zich richten op .NET aan uw app. Zie het CodePagesEncodingProvider onderwerp voor meer informatie.

Een coderingsklasse selecteren

Als u de mogelijkheid hebt om de codering te kiezen die door uw toepassing moet worden gebruikt, moet u een Unicode-codering gebruiken, bij voorkeur UTF8Encoding of UnicodeEncoding. (.NET ondersteunt ook een derde Unicode-codering, UTF32Encoding.)

Als u van plan bent om een ASCII-codering (ASCIIEncoding) te gebruiken, kiest u UTF8Encoding in plaats daarvan. De twee coderingen zijn identiek voor de ASCII-tekenset, maar UTF8Encoding heeft de volgende voordelen:

  • Het kan elk Unicode-teken vertegenwoordigen, terwijl ASCIIEncoding alleen de Unicode-tekenwaarden tussen U+0000 en U+007F worden ondersteund.

  • Het biedt foutdetectie en betere beveiliging.

  • Het is zo snel mogelijk afgestemd en moet sneller zijn dan elke andere codering. Zelfs voor inhoud die volledig ASCII is, zijn bewerkingen die worden UTF8Encoding uitgevoerd sneller dan bewerkingen met ASCIIEncoding.

U moet overwegen alleen te gebruiken ASCIIEncoding voor verouderde toepassingen. Zelfs voor oudere toepassingen is het UTF8Encoding echter een betere keuze om de volgende redenen (ervan uitgaande dat standaardinstellingen worden gebruikt):

  • Als uw toepassing inhoud bevat die niet strikt ASCII is en deze codeert met ASCIIEncoding, codeert elk niet-ASCII-teken als een vraagteken (?). Als de toepassing deze gegevens vervolgens ontsleutelt, gaat de informatie verloren.

  • Als uw toepassing inhoud heeft die niet strikt ASCII is en codeert UTF8Encoding, lijkt het resultaat onleesbaar als deze wordt geïnterpreteerd als ASCII. Als de toepassing echter een UTF-8-decoder gebruikt om deze gegevens te decoderen, worden de gegevens een retour uitgevoerd.

In een webtoepassing moeten tekens die naar de client worden verzonden als reactie op een webaanvraag overeenkomen met de codering die op de client wordt gebruikt. In de meeste gevallen moet u de HttpResponse.ContentEncoding eigenschap instellen op de waarde die door de HttpRequest.ContentEncoding eigenschap wordt geretourneerd om tekst weer te geven in de codering die de gebruiker verwacht.

Een coderingsobject gebruiken

Een encoder converteert een tekenreeks (meestal Unicode-tekens) naar het numerieke equivalent (byte). U kunt bijvoorbeeld een ASCII-encoder gebruiken om Unicode-tekens te converteren naar ASCII, zodat deze in de console kunnen worden weergegeven. Als u de conversie wilt uitvoeren, roept u de Encoding.GetBytes methode aan. Als u wilt bepalen hoeveel bytes er nodig zijn om de gecodeerde tekens op te slaan voordat u de codering uitvoert, kunt u de GetByteCount methode aanroepen.

In het volgende voorbeeld wordt één bytematrix gebruikt om tekenreeksen in twee afzonderlijke bewerkingen te coderen. Er wordt een index onderhouden die de beginpositie in de bytematrix aangeeft voor de volgende set MET ASCII-gecodeerde bytes. Hiermee wordt de ASCIIEncoding.GetByteCount(String) methode aangeroepen om ervoor te zorgen dat de bytematrix groot genoeg is voor de gecodeerde tekenreeks. Vervolgens wordt de ASCIIEncoding.GetBytes(String, Int32, Int32, Byte[], Int32) methode aangeroepen om de tekens in de tekenreeks te coderen.

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.

Een decoder converteert een bytematrix die een bepaalde tekencodering weerspiegelt in een reeks tekens, in een tekenmatrix of in een tekenreeks. Als u een bytematrix wilt decoderen in een tekenmatrix, roept u de Encoding.GetChars methode aan. Als u een bytematrix wilt decoderen in een tekenreeks, roept u de GetString methode aan. Als u wilt bepalen hoeveel tekens er nodig zijn om de gedecodeerde bytes op te slaan voordat u de decodering uitvoert, kunt u de GetCharCount methode aanroepen.

In het volgende voorbeeld worden drie tekenreeksen gecodeerd en vervolgens gedecodeerd in één matrix met tekens. Er wordt een index onderhouden die de beginpositie in de tekenmatrix aangeeft voor de volgende set gedecodeerde tekens. Hiermee wordt de GetCharCount methode aangeroepen om ervoor te zorgen dat de tekenmatrix groot genoeg is voor alle gedecodeerde tekens. Vervolgens wordt de ASCIIEncoding.GetChars(Byte[], Int32, Int32, Char[], Int32) methode aangeroepen om de bytematrix te decoderen.

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.

De coderings- en decoderingsmethoden van een klasse die is afgeleid van Encoding , zijn ontworpen om te werken aan een volledige set gegevens; dat wil gezegd dat alle gegevens die moeten worden gecodeerd of gedecodeerd, worden geleverd in één methodeaanroep. In sommige gevallen zijn gegevens echter beschikbaar in een stroom en kunnen de gegevens die moeten worden gecodeerd of gedecodeerd, alleen beschikbaar zijn vanuit afzonderlijke leesbewerkingen. Hiervoor moet de coderings- of decoderingsbewerking elke opgeslagen status onthouden van de vorige aanroep. Methoden van klassen die zijn afgeleid van Encoder en Decoder kunnen coderings- en decoderingsbewerkingen verwerken die meerdere methodeaanroepen omvatten.

Een Encoder object voor een bepaalde codering is beschikbaar in de eigenschap van Encoding.GetEncoder die codering. Een Decoder object voor een bepaalde codering is beschikbaar vanuit de eigenschap van Encoding.GetDecoder die codering. Voor decoderingsbewerkingen moet u er rekening mee houden dat klassen die zijn afgeleid van Decoder een Decoder.GetChars methode, maar ze geen methode hebben die overeenkomt met Encoding.GetString.

In het volgende voorbeeld ziet u het verschil tussen het gebruik van de Encoding.GetString en Decoder.GetChars methoden voor het decoderen van een Unicode-bytematrix. In het voorbeeld wordt een tekenreeks gecodeerd die een aantal Unicode-tekens bevat aan een bestand en gebruikt u vervolgens de twee decoderingsmethoden om ze tien bytes tegelijk te decoderen. Omdat een surrogaatpaar plaatsvindt in de tiende en elfde bytes, wordt het gedecodeerd in afzonderlijke methodeaanroepen. Zoals in de uitvoer wordt weergegeven, kan de Encoding.GetString methode de bytes niet correct decoderen en in plaats daarvan vervangen door U+FFFD (VERVANGEND TEKEN). Aan de andere kant kan de Decoder.GetChars methode de bytematrix decoderen om de oorspronkelijke tekenreeks op te halen.

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

Een terugvalstrategie kiezen

Wanneer een methode een teken probeert te coderen of decoderen, maar er geen toewijzing bestaat, moet er een terugvalstrategie worden geïmplementeerd die bepaalt hoe de mislukte toewijzing moet worden verwerkt. Er zijn drie soorten terugvalstrategieën:

  • Beste terugval

  • Vervangende terugval

  • Terugval van uitzondering

Belangrijk

De meest voorkomende problemen bij coderingsbewerkingen treden op wanneer een Unicode-teken niet kan worden toegewezen aan een bepaalde codepaginacodering. De meest voorkomende problemen bij decoderingsbewerkingen treden op wanneer ongeldige bytereeksen niet kunnen worden omgezet in geldige Unicode-tekens. Om deze redenen moet u weten welke terugvalstrategie een bepaald coderingsobject gebruikt. Indien mogelijk moet u de terugvalstrategie opgeven die wordt gebruikt door een coderingsobject wanneer u het object instantiëren.

Beste terugval

Wanneer een teken geen exacte overeenkomst heeft in de doelcodering, kan de encoder proberen deze toe te wijzen aan een vergelijkbaar teken. (Best fit fallback is meestal een codering in plaats van een decoderingsprobleem. Er zijn zeer weinig codepagina's die tekens bevatten die niet kunnen worden toegewezen aan Unicode.) De meest geschikte terugval is de standaardinstelling voor codepagina- en dubbel-bytetekensetcoderingen die worden opgehaald door de Encoding.GetEncoding(Int32) en Encoding.GetEncoding(String) overbelasting.

Notitie

In theorie ondersteunen de Unicode-coderingsklassen in .NET (UTF8Encoding, UnicodeEncodingen UTF32Encoding) elk teken in elke tekenset, zodat ze kunnen worden gebruikt om problemen met het beste terugval te voorkomen.

De best passende strategieën variëren voor verschillende codepagina's. Voor sommige codepagina's worden Latijnse tekens met volledige breedte bijvoorbeeld toegewezen aan de meest voorkomende Latijnse tekens met halve breedte. Voor andere codepagina's wordt deze toewijzing niet gemaakt. Zelfs onder een agressieve strategie die het beste past, is er geen denkbare pasvorm voor sommige tekens in sommige coderingen. Een Chinese ideograph heeft bijvoorbeeld geen redelijke toewijzing aan codepagina 1252. In dit geval wordt een vervangende tekenreeks gebruikt. Deze tekenreeks is standaard slechts één VRAAGTEKEN (U+003F).

Notitie

Best passende strategieën worden niet gedetailleerd gedocumenteerd. Er worden echter verschillende codepagina's beschreven op de website van het Unicode Consortium. Raadpleeg het readme.txt bestand in die map voor een beschrijving van het interpreteren van de toewijzingsbestanden.

In het volgende voorbeeld wordt codepagina 1252 (de Windows-codepagina voor West-Europese talen) gebruikt om de beste toewijzing en de nadelen ervan te illustreren. De Encoding.GetEncoding(Int32) methode wordt gebruikt voor het ophalen van een coderingsobject voor codepagina 1252. Standaard wordt een best passende toewijzing gebruikt voor Unicode-tekens die niet worden ondersteund. In het voorbeeld wordt een tekenreeks geïnstantieerd die drie niet-ASCII-tekens bevat: CIRCLED LATIN CAPITAL LETTER S (U+24C8), SUPERSCRIPT FIVE (U+2075) en INFINITY (U+221E), gescheiden door spaties. Zoals in de uitvoer van het voorbeeld wordt weergegeven, worden de drie oorspronkelijke niet-spatietekens vervangen door VRAAGTEKEN (U+003F), DIGIT FIVE (U+0035) en DIGIT ACHT (U+0038). DIGIT ACHT is een bijzonder slechte vervanging voor het niet-ondersteunde INFINITY-teken en HET VRAAGTEKEN geeft aan dat er geen toewijzing beschikbaar was voor het oorspronkelijke teken.

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

De meest geschikte toewijzing is het standaardgedrag voor een Encoding object dat Unicode-gegevens codeert in codepaginagegevens en er oudere toepassingen zijn die afhankelijk zijn van dit gedrag. De meeste nieuwe toepassingen moeten echter om veiligheidsredenen het best passende gedrag vermijden. Toepassingen mogen bijvoorbeeld geen domeinnaam plaatsen via een best passende codering.

Notitie

U kunt ook een aangepaste best passende terugvaltoewijzing implementeren voor een codering. Zie de sectie Een aangepaste terugvalstrategie implementeren voor meer informatie.

Als terugval het meest geschikt is voor een coderingsobject, kunt u een andere terugvalstrategie kiezen wanneer u een Encoding object ophaalt door de Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) of Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) overbelasting aan te roepen. De volgende sectie bevat een voorbeeld dat elk teken vervangt dat niet kan worden toegewezen aan codepagina 1252 door een sterretje (*).

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

Vervangende terugval

Wanneer een teken geen exacte overeenkomst heeft in het doelschema, maar er geen geschikt teken is waaraan het kan worden toegewezen, kan de toepassing een vervangend teken of een tekenreeks opgeven. Dit is het standaardgedrag voor de Unicode-decoder, die een twee-bytereeks vervangt die niet kan worden gedecodeerd met REPLACEMENT_CHARACTER (U+FFFD). Het is ook het standaardgedrag van de ASCIIEncoding klasse, dat elk teken vervangt dat het niet kan coderen of decoderen met een vraagteken. In het volgende voorbeeld ziet u de vervanging van tekens voor de Unicode-tekenreeks uit het vorige voorbeeld. Zoals in de uitvoer wordt weergegeven, wordt elk teken dat niet kan worden gedecodeerd in een ASCII-bytewaarde vervangen door 0x3F, de ASCII-code voor een vraagteken.

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

.NET bevat de EncoderReplacementFallback en DecoderReplacementFallback klassen, die een vervangende tekenreeks vervangen als een teken niet exact wordt toegewezen in een coderings- of decoderingsbewerking. Deze vervangende tekenreeks is standaard een vraagteken, maar u kunt een overbelasting van een klasseconstructor aanroepen om een andere tekenreeks te kiezen. Normaal gesproken is de vervangende tekenreeks één teken, hoewel dit geen vereiste is. In het volgende voorbeeld wordt het gedrag van de codepagina 1252-encoder gewijzigd door een EncoderReplacementFallback object te instantiëren dat een sterretje (*) gebruikt als vervangingstekenreeks.

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

Notitie

U kunt ook een vervangingsklasse implementeren voor een codering. Zie de sectie Een aangepaste terugvalstrategie implementeren voor meer informatie.

Naast VRAAGTEKEN (U+003F) wordt het Unicode REPLACEMENT CHARACTER (U+FFFD) vaak gebruikt als een vervangende tekenreeks, met name bij het decoderen van bytereeksen die niet kunnen worden omgezet in Unicode-tekens. U kunt echter elke vervangende tekenreeks kiezen en deze kan meerdere tekens bevatten.

Terugval van uitzondering

In plaats van een best passende terugval of een vervangende tekenreeks te bieden, kan een encoder een EncoderFallbackException code genereren als deze een set tekens niet kan coderen en een decoder een DecoderFallbackException kan genereren als een bytematrix niet kan worden gedecodeerd. Als u een uitzondering wilt genereren in coderings- en decoderingsbewerkingen, levert u respectievelijk een EncoderExceptionFallback object en een DecoderExceptionFallback object aan de Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) methode. Het volgende voorbeeld illustreert het terugvallen van uitzonderingen met de ASCIIEncoding klasse.

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.

Notitie

U kunt ook een aangepaste uitzonderingshandler implementeren voor een coderingsbewerking. Zie de sectie Een aangepaste terugvalstrategie implementeren voor meer informatie.

De EncoderFallbackException en DecoderFallbackException objecten bevatten de volgende informatie over de voorwaarde die de uitzondering heeft veroorzaakt:

Hoewel de EncoderFallbackException en DecoderFallbackException objecten voldoende diagnostische informatie over de uitzondering bieden, bieden ze geen toegang tot de coderings- of decoderingsbuffer. Daarom staan ze niet toe dat ongeldige gegevens worden vervangen of gecorrigeerd binnen de coderings- of decoderingsmethode.

Een aangepaste terugvalstrategie implementeren

Naast de best passende toewijzing die intern door codepagina's wordt geïmplementeerd, bevat .NET de volgende klassen voor het implementeren van een terugvalstrategie:

Daarnaast kunt u een aangepaste oplossing implementeren die gebruikmaakt van het beste passende terugval, vervangende terugval of terugval van uitzonderingen door de volgende stappen uit te voeren:

  1. Een klasse afleiden van EncoderFallback voor coderingsbewerkingen en van DecoderFallback voor decoderingsbewerkingen.

  2. Een klasse afleiden van EncoderFallbackBuffer voor coderingsbewerkingen en van DecoderFallbackBuffer voor decoderingsbewerkingen.

  3. Als de vooraf gedefinieerde EncoderFallbackException en DecoderFallbackException klassen niet aan uw behoeften voldoen, moet u een klasse afleiden van een uitzonderingsobject zoals Exception of ArgumentException.

Afgeleid van EncoderFallback of DecoderFallback

Als u een aangepaste terugvaloplossing wilt implementeren, moet u een klasse maken van waaruit bewerkingen EncoderFallback worden overgenomen voor coderingsbewerkingen en van DecoderFallback voor decoderingsbewerkingen. Exemplaren van deze klassen worden doorgegeven aan de Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) methode en fungeren als intermediair tussen de coderingsklasse en de terugval-implementatie.

Wanneer u een aangepaste terugvaloplossing voor een encoder of decoder maakt, moet u de volgende leden implementeren:

Afgeleid van EncoderFallbackBuffer of DecoderFallbackBuffer

Als u een aangepaste terugvaloplossing wilt implementeren, moet u ook een klasse maken die wordt overgenomen van EncoderFallbackBuffer voor coderingsbewerkingen en van DecoderFallbackBuffer voor decoderingsbewerkingen. Exemplaren van deze klassen worden geretourneerd door de CreateFallbackBuffer methode van de EncoderFallback en DecoderFallback klassen. De EncoderFallback.CreateFallbackBuffer methode wordt aangeroepen door de encoder wanneer het eerste teken tegenkomt dat deze niet kan coderen en de DecoderFallback.CreateFallbackBuffer methode wordt aangeroepen door de decoder wanneer er een of meer bytes worden aangeroepen die niet kunnen worden gedecodeerd. De EncoderFallbackBuffer en DecoderFallbackBuffer klassen bieden de terugval-implementatie. Elk exemplaar vertegenwoordigt een buffer die de terugvaltekens bevat die het teken vervangen dat niet kan worden gecodeerd of de bytereeks die niet kan worden gedecodeerd.

Wanneer u een aangepaste terugvaloplossing voor een encoder of decoder maakt, moet u de volgende leden implementeren:

  • De EncoderFallbackBuffer.Fallback of DecoderFallbackBuffer.Fallback methode. EncoderFallbackBuffer.Fallback wordt door de encoder aangeroepen om de terugvalbuffer te voorzien van informatie over het teken dat niet kan worden gecodeerd. Omdat het teken dat moet worden gecodeerd een surrogaatpaar kan zijn, is deze methode overbelast. Eén overbelasting wordt doorgegeven aan het teken dat moet worden gecodeerd en de bijbehorende index in de tekenreeks. De tweede overbelasting wordt doorgegeven aan het hoge en lage surrogaat, samen met de index in de tekenreeks. De DecoderFallbackBuffer.Fallback methode wordt aangeroepen door de decoder om de terugvalbuffer te voorzien van informatie over de bytes die niet kunnen worden gedecodeerd. Deze methode wordt doorgegeven aan een matrix van bytes die niet kan worden gedecodeerd, samen met de index van de eerste byte. De terugvalmethode moet worden geretourneerd true als de terugvalbuffer een best passend of vervangend teken of tekens kan leveren; anders moet deze worden geretourneerd false. Voor een terugval van uitzonderingen moet de terugvalmethode een uitzondering genereren.

  • De EncoderFallbackBuffer.GetNextChar of DecoderFallbackBuffer.GetNextChar methode, die herhaaldelijk wordt aangeroepen door de encoder of decoder om het volgende teken op te halen uit de terugvalbuffer. Wanneer alle terugvaltekens zijn geretourneerd, moet de methode U+0000 retourneren.

  • De EncoderFallbackBuffer.Remaining of DecoderFallbackBuffer.Remaining eigenschap, waarmee het aantal tekens wordt geretourneerd dat in de terugvalbuffer resteert.

  • De EncoderFallbackBuffer.MovePrevious of DecoderFallbackBuffer.MovePrevious methode, waarmee de huidige positie in de terugvalbuffer naar het vorige teken wordt verplaatst.

  • De EncoderFallbackBuffer.Reset of DecoderFallbackBuffer.Reset methode, waarmee de terugvalbuffer opnieuw wordt geïnitialiseerd.

Als de terugval-implementatie een best passende terugval is of een vervangende terugval, blijven de klassen afgeleid van EncoderFallbackBuffer en DecoderFallbackBuffer onderhouden ook twee privé-exemplaarvelden: het exacte aantal tekens in de buffer en de index van het volgende teken in de buffer om te retourneren.

Een encoderFallback-voorbeeld

Een eerder voorbeeld gebruikte vervangingsback om Unicode-tekens te vervangen die niet overeenkomen met ASCII-tekens met een sterretje (*). In het volgende voorbeeld wordt een aangepaste best passende terugvalimplementatie gebruikt om een betere toewijzing van niet-ASCII-tekens te bieden.

Met de volgende code wordt een klasse gedefinieerd CustomMapper die is afgeleid van EncoderFallback om de best passende toewijzing van niet-ASCII-tekens af te handelen. De CreateFallbackBuffer methode retourneert een CustomMapperFallbackBuffer object, dat de EncoderFallbackBuffer implementatie levert. De CustomMapper klasse gebruikt een Dictionary<TKey,TValue> object voor het opslaan van de toewijzingen van niet-ondersteunde Unicode-tekens (de sleutelwaarde) en de bijbehorende 8-bits tekens (die worden opgeslagen in twee opeenvolgende bytes in een 64-bits geheel getal). Als u deze toewijzing beschikbaar wilt maken voor de terugvalbuffer, wordt het CustomMapper exemplaar doorgegeven als een parameter aan de CustomMapperFallbackBuffer klasseconstructor. Omdat de langste toewijzing de tekenreeks 'INF' is voor het Unicode-teken U+221E, retourneert de MaxCharCount eigenschap 3.

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

De volgende code definieert de CustomMapperFallbackBuffer klasse, die is afgeleid van EncoderFallbackBuffer. De woordenlijst met best passende toewijzingen en die in het exemplaar is gedefinieerd, is beschikbaar via de CustomMapper klasseconstructor. De Fallback methode retourneert true als een van de Unicode-tekens die de ASCII-encoder niet kan coderen, zijn gedefinieerd in de toewijzingswoordenlijst. Anders wordt deze geretourneerd false. Voor elke terugval geeft de privévariabele count het aantal tekens aan dat moet worden geretourneerd, en de privévariabele index geeft de positie in de tekenreeksbuffer aan, charsToReturnvan het volgende teken dat moet worden geretourneerd.

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

Met de volgende code wordt vervolgens een instantie van het CustomMapper object geïnstitueert en aan de Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) methode doorgegeven. De uitvoer geeft aan dat de best passende terugvalimplementatie de drie niet-ASCII-tekens in de oorspronkelijke tekenreeks verwerkt.

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

Zie ook