Codificação de caracteres a.NET Framework

Os caracteres são entidades abstratas que podem ser representadas de diferentes maneiras. Uma codificação de caractere é um sistema de pares de cada caractere em um conjunto com algum valor que representa o caractere de caracteres com suporte. Por exemplo, o código Morse é um caractere de codificação que pares de cada caractere do alfabeto romano com um padrão de pontos e traços são adequados para transmissão através de linhas de telégrafo. Uma codificação de caracteres para os pares de computadores cada caractere em um conjunto com um valor numérico que representa o caractere de caracteres com suporte. Uma codificação de caractere tem dois componentes distintos:

  • Um codificador, que converte uma seqüência de caracteres em uma seqüência de valores numéricos (bytes).

  • Um decodificador, que converte uma seqüência de bytes em uma seqüência de caracteres.

Codificação de caracteres descreve as regras pelas quais um codificador e um decodificador de operam. Por exemplo, o UTF8Encoding classe descreve as regras de codificação e decodificação de 8-bit Unicode Transformation Format (UTF-8), que usa um a quatro bytes para representar um caractere Unicode único. Codificação e decodificação também podem incluir a validação. Por exemplo, o UnicodeEncoding classe verifica todos os substitutos para certificar-se de que eles constituem pares de substituto válido. (Um par substituto consiste de um caractere com um ponto de código que varia de U + D800 a U + DBFF seguido por um caractere com um ponto de código que varia de U + DC00 a U + DFFF). Uma estratégia de fallback determina como um codificador trata caracteres inválidos ou como um decodificador trata bytes inválidos.

Observação de cuidadoCuidado

A.Classes de codificação do NET Framework fornecem uma maneira para armazenar e converter os dados de caractere.Eles não devem ser usados para armazenar dados binários em forma de seqüência.Dependendo da codificação usada, como converter dados binários como seqüência de formato com as classes de codificação pode apresentar um comportamento inesperado e produzir dados imprecisos ou corrompidos.Para converter dados binários em um formulário de cadeia de caracteres, use o Convert.ToBase64String(Byte[]) método.

Aplicativos destinados o common language runtime usam codificadores para mapear as representações de caracteres Unicode suportadas pelo common language runtime para outros esquemas de codificação. Eles usam decodificadores para mapear caracteres de codificações não-Unicode para Unicode.

Este tópico consiste nas seções a seguir:

Codificações na.NET Framework

Todas as classes codificação de caracteres a.NET Framework herdam o System.Text.Encoding classe, que é uma classe abstrata que define a funcionalidade comum a todas as codificações de caractere. Para acessar os objetos individuais de codificação implementados na.NET Framework, faça o seguinte:

  • Use as propriedades estáticas da Encoding classe, que retornam objetos que representam as codificações de caractere padrão disponíveis na.NET Framework (ASCII, UTF-7, UTF-8, UTF-16 e UTF-32). Por exemplo, o Encoding.Unicode propriedade retorna um UnicodeEncoding objeto. Cada objeto usa a substituição de fallback para seqüências de caracteres de identificador que ele não é possível codificar e bytes que ele não é possível decodificar. (Para obter mais informações, consulte o Replacement Fallback seção.)

  • Ligue para construtor de classe a codificação. Objetos para ASCII, UTF-7, UTF-8, UTF-16 e UTF-32 codificações podem ser instanciados dessa maneira. Por padrão, cada objeto usa a substituição de fallback para manipular seqüências de caracteres que ele não é possível codificar e bytes que ele não é possível decodificar, mas você pode especificar que uma exceção deve ser lançada em vez disso. (Para obter mais informações, consulte o Replacement Fallback e Exception Fallback seções.)

  • Chamar o Encoding.Encoding(Int32) construtor e passá-lo um inteiro que representa a codificação. Objetos de codificação padrão usam o fallback de substituição e a página de código e a codificação do uso de objetos fallback ajuste perfeito para seqüências de caracteres de identificador que eles não é possível codificar e bytes que eles não é possível decodificar de conjunto de caracteres de byte duplo (DBCS). (Para obter mais informações, consulte o Best-Fit Fallback seção.)

  • Chamar o o métodoEncoding.GetEncoding , que retorna qualquer padrão, a página de código ou a codificação de DBCS disponíveis na.NET Framework. Sobrecargas permitem que você especificar um objeto de fallback para o decodificador e codificador.

Observação

O padrão Unicode atribui um ponto de código (número) e um nome para cada caractere em todos os scripts com suporte.Por exemplo, o caractere "A" é representado por U + 0041 do ponto de código e o nome "A de LETRA maiúscula latina".As codificações Unicode Transformation Format (UTF) definem maneiras de codificar esse ponto de código em uma seqüência de bytes de um ou mais.Um esquema de codificação Unicode simplifica o desenvolvimento de aplicativos do mundo porque ela permite que os caracteres de qualquer conjunto de caracteres a serem representadas em uma única codificação.Os desenvolvedores de aplicativos não têm mais controlar o esquema de codificação que foi utilizado para produzir caracteres para um idioma específico ou sistema de escrita e dados podem ser compartilhados entre sistemas internacionalmente sem corrompido.

A.NET Framework oferece suporte a três codificações, definidas pelo padrão Unicode: UTF-8, UTF-16 e UTF-32.Para obter mais informações, consulte o padrão Unicode na Unicode home page.

Você pode recuperar informações sobre todas as codificações disponíveis na.NET Framework, chamando o Encoding.GetEncodings método. A.NET Framework oferece suporte a sistemas listados na tabela a seguir de codificação de caracteres.

Codificação

Classe

Descrição

Vantagens/desvantagens.

ASCII

ASCIIEncoding

Codifica um intervalo limitado de caracteres usando sete bits inferiores de um byte.

Como essa codificação só oferece suporte a valores de caracteres de U + 0000 até U + 007F, na maioria dos casos é inadequada para aplicativos internacionalizados.

UTF-7

UTF7Encoding

Representa caracteres como seqüências de caracteres ASCII de 7 bits. Caracteres Unicode de não-ASCII são representados por uma seqüência de escape de caracteres ASCII.

UTF-7 oferece suporte a protocolos como, por exemplo, email e grupo de notícias. No entanto, UTF-7 não é particularmente seguro ou robusta. Em alguns casos, alterar um bit pode alterar radicalmente a interpretação de uma seqüência de caracteres UTF-7 inteira. Em outros casos, seqüências de caracteres UTF-7 diferentes podem codificar o mesmo texto. Para obter seqüências que incluem caracteres não-ASCII, UTF-7 requer mais espaço que o UTF-8 e codificação/decodificação é mais lento. Conseqüentemente, você deve usar UTF-8 em vez de UTF-7 se possível.

UTF-8

UTF8Encoding

Representa a cada ponto de código Unicode como uma seqüência de um a quatro bytes.

UTF-8 oferece suporte a tamanhos de dados de 8 bits e funciona bem com muitos sistemas operacionais de existentes. Para o intervalo ASCII de caracteres, o UTF-8 é idêntica à codificação ASCII e permite um amplo conjunto de caracteres. Entretanto, para scripts do chinês-japonês-coreano (CJK), UTF-8 pode exigir a três bytes para cada caractere e pode potencialmente causar maiores tamanhos de dados que UTF-16. Observe que algumas vezes a quantidade de dados ASCII, como, por exemplo, as marcas HTML, justifica o tamanho aumentado para o intervalo CJK.

UTF-16

UnicodeEncoding

Representa a cada ponto de código Unicode como uma seqüência de um ou dois inteiros de 16 bits. Caracteres do Unicode mais comuns exigem apenas um ponto de código UTF-16, embora caracteres suplementares do Unicode (U + 10000 e maior) exigem dois pontos de código UTF-16 substituto. Ambas as ordens de byte little-endian e big-endian são suportadas.

Codificação UTF-16 é usada pelo common language runtime para representar Char e String valores e ele é usado pelo sistema operacional Windows para representar WCHAR valores.

UTF-32

UTF32Encoding

Representa cada ponto de código Unicode como um inteiro de 32 bits. Ambas as ordens de byte little-endian e big-endian são suportadas.

A codificação UTF-32 é usado quando aplicativos querem evitar o comportamento de ponto de código substituto de codificação UTF-16 em sistemas operacionais, para o qual espaço codificado é muito importante. Único glifos renderizados em uma exibição ainda podem ser codificados com mais de um caractere de UTF-32.

Codificações ANSI/ISO.

Fornece suporte para uma variedade de páginas de código. Em sistemas operacionais Windows, páginas de código são usadas para dar suporte a um idioma específico ou grupo de idiomas. Para uma tabela que lista as páginas de código que suporte o.NET Framework, consulte o Encoding classe. Você pode recuperar um objeto de codificação para uma determinada página de código chamando o Encoding.GetEncoding(Int32) método.

Uma página de código contém 256 pontos de código e é baseada em zero. Na maioria das páginas de código, 0 a 127 pontos de código representam o conjunto de caracteres ASCII e pontos de código 128 a 255 diferirem significativamente entre as páginas de código. Por exemplo, a página de código 1252 fornece os caracteres para latino escrever sistemas, incluindo inglês, alemão e francês. Os últimos 128 pontos de código na página de código 1252 contenham os caracteres de ênfase. A página de código 1253 fornece códigos de caracteres que são necessários no sistema de escrita grego. Os últimos 128 pontos de código na página de código 1253 contenham os caracteres gregos. Como resultado, um aplicativo que depende de páginas de código ANSI não é possível armazenar grego e alemão no mesmo fluxo de texto, a menos que ele inclui um identificador que indica a página de código referenciado.

Conjunto de caracteres de byte duplo (DBCS) codificações

Oferece suporte a idiomas, como chinês, japonês e coreano, que contêm mais de 256 caracteres. Um DBCS, um par de pontos de código (double byte) representa cada caractere. O Encoding.IsSingleByte retorna a propriedade false para codificações DBCS. Você pode recuperar um objeto de codificação para um determinado DBCS chamando o Encoding.GetEncoding(Int32) método.

Um DBCS, um par de pontos de código (double byte) representa cada caractere. Quando um aplicativo manipula dados DBCS, o primeiro byte de um caractere DBCS (o byte inicial) é processado em combinação com o byte de seguimento que segue imediatamente. Como um único par de pontos de código de byte duplo pode representar caracteres diferentes dependendo da página de código, esse esquema ainda não permite a combinação de dois idiomas, como, por exemplo, japonês e chinês, no mesmo fluxo de dados.

Essas codificações lhe permitem trabalhar com caracteres Unicode, bem como com codificações são mais comumente usadas em aplicativos herdados. Além disso, você pode criar uma codificação personalizada, definindo uma classe que deriva de Encoding e substituindo os membros.

Selecionar uma classe de codificação

Se você tiver a oportunidade de escolher a codificação a ser usado pelo seu aplicativo, você deve usar um Unicode codificação, preferencialmente em um UTF8Encoding ou UnicodeEncoding. (O.NET Framework também suporta uma terceira codificação Unicode, UTF32Encoding.)

Se você estiver planejando usar uma codificação ASCII (ASCIIEncoding), escolha UTF8Encoding em vez disso. As duas codificações são idênticas para o conjunto de caracteres ASCII, mas UTF8Encoding tem as seguintes vantagens:

  • Ela pode representar cada caractere Unicode, enquanto ASCIIEncoding suporta apenas o Unicode caracteres valores entre U + 0000 e U + 007F.

  • Ele fornece detecção de erros e maior segurança.

  • Ele foi ajustado para ser o mais rápido possível e deve ser mais rápido do que qualquer outra codificação. Mesmo para conteúdo que é totalmente ASCII, as operações realizadas com UTF8Encoding são mais rápidas que as operações executadas com ASCIIEncoding.

Você deve considerar o uso ASCIIEncoding somente para aplicativos herdados. No entanto, mesmo para aplicativos herdados, UTF8Encoding pode ser uma escolha melhor pelos seguintes motivos (supondo que as configurações padrão):

  • Se seu aplicativo tiver conteúdo que não seja estritamente ASCII e codifica-lo com ASCIIEncoding, cada caractere não-ASCII codifica como um ponto de interrogação (?). Se o aplicativo decodifica esses dados, as informações serão perdidas.

  • Se seu aplicativo tiver conteúdo que não seja estritamente ASCII e codifica-lo com UTF8Encoding, o resultado parece ininteligível se interpretado como ASCII. No entanto, se o aplicativo usa um decodificador de UTF-8 para decodificar os dados, o dados realiza uma viagem com êxito.

Em um aplicativo da web, enviados ao cliente em resposta a uma solicitação da web de caracteres devem refletir a codificação usada no cliente. Na maioria dos casos, você deve definir o HttpResponse.ContentEncoding o valor retornado pela propriedade de HttpRequest.ContentEncoding propriedade para exibir o texto na codificação que o usuário espera.

Usando o objeto de codificação

Um codificador converte uma seqüência de caracteres (mais comumente, o caracteres Unicode) seu numérico (bytes) equivalente. Por exemplo, você pode usar um codificador de ASCII para converter caracteres Unicode em ASCII, para que possam ser exibidos no console. Para executar a conversão, você chamar o Encoding.GetBytes método. Se você quiser determinar quantos bytes são necessários para armazenar os caracteres codificados antes de executar a codificação, você pode chamar o GetByteCount método.

O exemplo a seguir usa uma matriz de byte único para codificar seqüências de caracteres em duas operações separadas. Ele mantém um índice que indica a posição inicial da matriz de bytes para o próximo conjunto de bytes codificados em ASCII. Ele chama o ASCIIEncoding.GetByteCount(String) método para garantir que a matriz de bytes é grande o suficiente para acomodar a seqüência de caracteres codificada. Em seguida, chama o ASCIIEncoding.GetBytes(String, Int32, Int32, Byte[], Int32) método para codificar caracteres na seqüência de caracteres.

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

Um decodificador converte uma matriz de bytes que reflete uma codificação de caractere particular em um conjunto de caracteres, em uma matriz de caracteres ou uma seqüência de caracteres. Para decodificar uma matriz de bytes em uma matriz de caracteres, você chamar o Encoding.GetChars método. Para decodificar uma matriz de bytes em uma seqüência de caracteres, você chamar o GetString método. Se você quiser determinar quantos caracteres são necessários para armazenar os bytes decodificados antes de executar a decodificação, você pode chamar o GetCharCount método.

O exemplo a seguir codifica o três seqüências de caracteres e, em seguida, decodifica-los em um único conjunto de caracteres. Ele mantém um índice que indica a posição inicial da matriz de caracteres para o próximo conjunto de caracteres decodificadas. Ele chama o GetCharCount método para garantir que a matriz de caracteres é grande o suficiente para acomodar todos os caracteres decodificada. Em seguida, chama o ASCIIEncoding.GetChars(Byte[], Int32, Int32, Char[], Int32) método para decodificar a matriz de bytes.

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

A codificação e decodificação de métodos de uma classe derivada de Encoding são projetados para trabalhar em um conjunto completo de dados; ou seja, todos os dados a ser codificado ou decodificado são fornecidos em um único método de chamada. No entanto, em alguns casos, dados estão disponíveis em um fluxo e os dados para ser codificado ou decodificado podem estar disponíveis apenas a partir de operações de leitura separadas. Isso requer que a operação de codificação ou decodificação, lembre-se de qualquer estado salvo de sua invocação anterior. Métodos de classes derivadas de Encoder e Decoder são capazes de lidar com a codificação e decodificação de operações que abrangem várias chamadas de método.

Um Encoder objeto para uma codificação específica está disponível a partir do codificação Encoding.GetEncoder propriedade. A Decoder objeto para uma codificação específica está disponível a partir do codificação Encoding.GetDecoder propriedade. Para operações de decodificação, observe que as classes derivadas de Decoder incluem uma Decoder.GetChars método, mas eles não têm um método que corresponde a Encoding.GetString.

O exemplo a seguir ilustra a diferença entre usar o Encoding.GetChars e Decoder.GetChars métodos para decodificar uma matriz de byte Unicode. O exemplo codifica uma seqüência de caracteres que contém alguns caracteres Unicode em um arquivo e, em seguida, usa os dois métodos de decodificação decodificá-las a dez bytes cada vez. Como um par substituto ocorre nos bytes décimo e o décimo primeiro, ele é decodificado em chamadas de método separado. Como mostra a saída, o Encoding.GetChars não é capaz de decodificar corretamente os bytes de método e substitui em vez da U + FFFD (CARACTERE de substituição). Por outro lado, o Decoder.GetChars método é capaz de decodificar com êxito a matriz de bytes para obter a seqüência original.

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

Escolhendo uma estratégia de Fallback

Quando um método tenta codificar ou decodificar um caractere, mas não existe mapeamento, ele deve implementar uma estratégia de fallback determina como o mapeamento de falha deve ser tratado. Existem três tipos de estratégias alternativas:

  • Melhor ajuste fallback

  • Substituição de fallback

  • Exceção de fallback

Observação importanteImportante

Os problemas mais comuns em operações de codificação ocorrem quando um caractere Unicode não pode ser mapeado para uma codificação de página de código em particular.Os problemas mais comuns na decodificação operações ocorrem quando as seqüências de bytes inválidos não podem ser traduzidas em caracteres Unicode válidos.Por esses motivos, você deve saber qual estratégia de fallback usa de um determinado objeto de codificação.Sempre que possível, você deve especificar a estratégia de fallback usada por um objeto de codificação ao instanciar o objeto.

Melhor ajuste Fallback

Quando um caractere não tem uma correspondência exata na codificação de destino, o codificador pode tentar mapeá-lo para um caractere semelhante. (Ajuste perfeito de fallback é principalmente uma codificação em vez de um problema de decodificação. Existem muito poucas páginas de código que contêm caracteres que não podem ser mapeados com êxito para Unicode). Melhor ajuste fallback é o padrão para a página de código e codificações são recuperadas de conjunto de caracteres de byte duplo de Encoding.GetEncoding(Int32) e Encoding.GetEncoding(String) sobrecargas.

Observação

Em teoria, as classes de codificação Unicode fornecido na.NET Framework (UTF8Encoding, UnicodeEncoding, e UTF32Encoding) suporte a cada caractere em cada conjunto de caracteres, para que possam ser usadas para eliminar problemas de fallback ajuste perfeito.

As estratégias de ajuste perfeitas variam para diferentes páginas de código, e eles não são documentados em detalhes. Por exemplo, para algumas páginas de código latino de largura total caracteres mapa de caracteres latino de meia largura mais comuns. Esse mapeamento não é feito para outras páginas de código. Mesmo em uma estratégia de ajuste perfeita agressiva, não há nenhum ajuste imaginável para alguns caracteres em alguns codificações. Por exemplo, um CJK chinês não tem nenhum mapeamento razoável para a página de código 1252. Nesse caso, uma seqüência de caracteres de substituição é usada. Por padrão, essa seqüência é apenas um único ponto de INTERROGAÇÃO (U + 003F).

O exemplo a seguir usa a página de código 1252 (a página de código de Windows para idiomas da Europa Ocidental) para ilustrar o mapeamento de ajuste perfeito e suas desvantagens. O Encoding.GetEncoding(Int32) método é usado para recuperar um objeto de codificação para a página de código 1252. Por padrão, ele usa um mapeamento de ajuste perfeito para caracteres Unicode que não suporta. O exemplo cria uma instância de uma seqüência de três caracteres não-ASCII - dentro de um CÍRCULO S de LETRA maiúscula latina (U + 24 C 8), SOBRESCRITO cinco (U + 2075) e infinito (U + 221E) - separados por espaços. Como mostra a saída do exemplo, quando a seqüência de caracteres é codificada, três caracteres que não seja espaço originais são substituídos por um ponto de INTERROGAÇÃO (U + 003F), DÍGITO cinco (U + 0035) e oito de DÍGITO (U + 0038). DÍGITO oito é uma substituição especialmente ruim para o caractere de infinito não suportado, e o ponto de INTERROGAÇÃO indica que nenhum mapeamento foi disponível para o caractere original.

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

Mapeamento de ajuste perfeito é o comportamento padrão para um Encoding objeto que codifica dados Unicode em dados da página de código e existem aplicativos legados que dependem de comportamento. No entanto, a maioria dos novos aplicativos devem evitar o comportamento de ajuste perfeito por motivos de segurança. Por exemplo, aplicativos não devem colocar um nome de domínio por meio de uma codificação de melhor ajuste.

Observação

Você também pode implementar um mapeamento de fallback melhor ajuste personalizado para uma codificação.Para obter mais informações, consulte o Implementing a Custom Fallback Strategy seção.

Se o melhor ajuste fallback é o padrão para um objeto de codificação, você pode escolher outra estratégia de fallback quando você recupera um Encoding objeto chamando o Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) ou Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) sobrecarga. A seção a seguir inclui um exemplo que substitui cada caractere que não pode ser mapeado para a página de código 1252 com um asterisco (*).

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

Fallback de substituição

Quando um caractere não tem uma correspondência exata do esquema de destino, mas não há nenhum apropriada de caracteres que podem ser mapeado para, o aplicativo pode especificar uma seqüência ou um caractere de substituição. Este é o comportamento padrão para o decodificador de Unicode, que substitui qualquer seqüência de dois bytes, ele não é possível decodificar com REPLACEMENT_CHARACTER (U + FFFD). Também é o comportamento padrão do ASCIIEncoding classe, que substitui cada caractere que não pode codificar ou decodificar com um ponto de interrogação. O exemplo a seguir ilustra a substituição de caractere para a seqüência de caracteres Unicode do exemplo anterior. Como mostra a saída, cada caractere que não pode ser decodificado em um valor de byte ASCII é substituído pelo 0x3F, que é o código ASCII para um ponto de interrogação.

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

A.NET Framework inclui o EncoderReplacementFallback e DecoderReplacementFallback classes, que substitua uma seqüência de caracteres de substituição se um caractere não mapeia exatamente em uma operação de codificação ou decodificação. Por padrão, essa seqüência de caracteres de substituição é um ponto de interrogação, mas você pode chamar uma sobrecarga do construtor de classe para escolher uma seqüência diferente. Normalmente, a seqüência de caracteres de substituição é um único caractere, embora isso não seja um requisito. O exemplo seguinte altera o comportamento do codificador de página 1252 código pela instanciação de um EncoderReplacementFallback objeto que usa um asterisco (*) como uma seqüência de caracteres de substituição.

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

Observação

Você também pode implementar uma classe de substituição para uma codificação.Para obter mais informações, consulte o Implementing a Custom Fallback Strategy seção.

Além de ao ponto de INTERROGAÇÃO (U + 003F), o CARÁCTER Unicode (U + FFFD) normalmente é usado como uma seqüência de caracteres de substituição, particularmente quando as seqüências de bytes não podem ser traduzidas com sucesso em caracteres Unicode de decodificação. Entretanto, você é livre para escolher qualquer seqüência de caracteres de substituição, e ele pode conter vários caracteres.

Fallback de exceção

Em vez de fornecer um melhor ajuste fallback ou uma seqüência de caracteres de substituição, um codificador pode lançar uma EncoderFallbackException se não é possível codificar um conjunto de caracteres e um decodificador pode lançar uma DecoderFallbackException se não é possível decodificar uma matriz de bytes. Lançar uma exceção na codificação e decodificação de operações, que você fornecer um EncoderExceptionFallback objeto e um DecoderExceptionFallback o objeto, respectivamente, para o Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) método. O exemplo a seguir ilustra a exceção de fallback com o ASCIIEncoding classe.

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

Observação

Você também pode implementar um manipulador de exceções personalizado para uma operação de codificação.Para obter mais informações, consulte o Implementing a Custom Fallback Strategy seção.

O EncoderFallbackException e DecoderFallbackException objetos fornecem as seguintes informações sobre a condição que causou a exceção:

Embora o EncoderFallbackException e DecoderFallbackException objetos fornecem informações de diagnóstico adequadas sobre a exceção, elas não fornecem acesso para o buffer de codificação ou decodificação. Portanto, eles não permitir que dados inválidos ser substituído ou corrigido dentro do método de codificação ou decodificação.

Implementar uma estratégia de Fallback personalizado

Além de para o mapeamento de ajuste perfeito é implementado internamente por páginas de código, o.NET Framework inclui as seguintes classes para implementar uma estratégia de fallback:

Além disso, você pode implementar uma solução personalizada que usa o melhor ajuste fallback, o fallback de substituição ou o fallback de exceção, seguindo estas etapas:

  1. Derivar uma classe de EncoderFallback para operações de codificação e de DecoderFallback para operações de decodificação.

  2. Derivar uma classe de EncoderFallbackBuffer para operações de codificação e de DecoderFallbackBuffer para operações de decodificação.

  3. If de fallback, exceção predefinido EncoderFallbackException e DecoderFallbackException classes não atenderem às suas necessidades, derive uma classe de um objeto de exceção, como Exception ou ArgumentException.

Derivando de EncoderFallback ou DecoderFallback

Para implementar uma solução personalizada de fallback, você deve criar uma classe que herda de EncoderFallback para operações de codificação e de DecoderFallback para operações de decodificação. Ocorrências dessas classes são passadas para o Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) método e servem como intermediário entre a classe de codificação e a implementação de fallback.

Quando você cria uma solução personalizada de fallback para um codificador ou decodificador, você deve implementar os seguintes membros:

Derivando de EncoderFallbackBuffer ou DecoderFallbackBuffer

Para implementar uma solução personalizada de fallback, você também deve criar uma classe que herda de EncoderFallbackBuffer para operações de codificação e de DecoderFallbackBuffer para operações de decodificação. Ocorrências dessas classes são retornadas pelo CreateFallbackBuffer método o EncoderFallback e DecoderFallback classes. O EncoderFallback.CreateFallbackBuffer método é chamado pelo codificador quando encontra o primeiro caractere que não seja capaz de codificar, e o DecoderFallback.CreateFallbackBuffer método é chamado pelo decodificador quando encontra um ou mais bytes que não é capaz de decodificar. O EncoderFallbackBuffer e DecoderFallbackBuffer classes fornecem a implementação de fallback. Cada instância representa um buffer que contém os caracteres de retorno que substituirão o caractere que não pode ser codificado ou a seqüência de bytes que não pode ser decodificada.

Quando você cria uma solução personalizada de fallback para um codificador ou decodificador, você deve implementar os seguintes membros:

Se a implementação de fallback é o melhor ajuste fallback ou um fallback de substituição, as classes derivadas de EncoderFallbackBuffer e DecoderFallbackBuffer também mantêm dois campos de instância privados: o número exato de caracteres no buffer; e o índice do próximo caractere no buffer para retornar.

Um exemplo de EncoderFallback

Um exemplo anterior usado fallback de substituição para substituir os caracteres Unicode que não corresponde a caracteres ASCII com um asterisco (*). O exemplo a seguir usa uma implementação personalizada de melhor ajuste fallback em vez disso, para fornecer a melhor mapeamento de caracteres não-ASCII.

O código a seguir define uma classe chamada CustomMapper que é derivada de EncoderFallback para lidar com o mapeamento de ajuste perfeito de todos os caracteres não-ASCII. Sua CreateFallbackBuffer método retorna um CustomMapperFallbackBuffer objeto, que fornece a EncoderFallbackBuffer de implementação. O CustomMapper classe usa uma Dictionary<TKey, TValue> o objeto para armazenar os mapeamentos de caracteres do Unicode sem suporte (o valor da chave) e seus caracteres de 8 bits correspondentes (que são armazenadas em dois bytes consecutivos em um inteiro de 64 bits). Para disponibilizar esse mapeamento para o buffer de fallback, o CustomMapper instância é passada como um parâmetro para o CustomMapperFallbackBuffer Construtor de classe. Porque o mapeamento mais longo é a seqüência de caracteres "INF" para o caractere do Unicode U + 221E, o MaxCharCount propriedade retorna 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
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; }
   } 
}

O código a seguir define o CustomMapperFallbackBuffer classe, que é derivada de EncoderFallbackBuffer. O dicionário que contém mapeamentos de ajuste perfeitos e que está definido na CustomMapper instância está disponível a partir do seu construtor de classe. Sua Fallback método retorna true se os caracteres Unicode que não é possível codificar o codificador ASCII são definidos no dicionário de mapeamento. Caso contrário, retornará false. Para cada fallback, particular count variável indica o número de caracteres que continuam a ser retornado e em particular index variável indica a posição do buffer de strings, charsToReturn, do próximo caractere de retorno.

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

Em seguida, o código a seguir instancia o CustomMapper object e passa uma instância para o Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) método. A saída indica que a implementação de fallback de ajuste perfeita com êxito manipula os três caracteres não ASCII na seqüência de caracteres original.

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

Consulte também

Referência

Encoder

Decoder

DecoderFallback

Encoding

EncoderFallback

Outros recursos

Codificação e localização

Histórico de alterações

Date

History

Motivo

Outubro de 2010

Revisado exaustivamente.

Aprimoramento de informações.