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.
Cuidado |
---|
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 |
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 |
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 |
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 |
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 |
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
Importante |
---|
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:
O EncoderFallbackException objeto inclui um IsUnknownSurrogate método, que indica se o caractere ou caracteres que não podem ser codificados representam um par substituto desconhecido (neste caso, o método retorna true) ou um único caractere desconhecido (neste caso, o método retorna false). Os caracteres do par substituto estão disponíveis a partir de EncoderFallbackException.CharUnknownHigh e EncoderFallbackException.CharUnknownLow Propriedades. O único caractere desconhecido está disponível a partir de EncoderFallbackException.CharUnknown propriedade. O EncoderFallbackException.Index propriedade indica a posição na seqüência em que o primeiro caractere que não pôde ser codificado foi encontrado.
O DecoderFallbackException objeto inclui um BytesUnknown propriedade que retorna uma matriz de bytes não pode ser decodificada. O DecoderFallbackException.Index propriedade indica a posição inicial de bytes desconhecido.
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:
Use EncoderReplacementFallback e EncoderReplacementFallbackBuffer para substituir caracteres em operações de codificação.
Use DecoderReplacementFallback e DecoderReplacementFallbackBuffer para substituir caracteres em operações de decodificação.
Use EncoderExceptionFallback e EncoderExceptionFallbackBuffer Lançar um EncoderFallbackException quando um caractere não pode ser codificado.
Use DecoderExceptionFallback e DecoderExceptionFallbackBuffer Lançar um DecoderFallbackException quando um caractere não pode ser decodificado.
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:
Derivar uma classe de EncoderFallback para operações de codificação e de DecoderFallback para operações de decodificação.
Derivar uma classe de EncoderFallbackBuffer para operações de codificação e de DecoderFallbackBuffer para operações de decodificação.
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:
O EncoderFallback.MaxCharCount ou DecoderFallback.MaxCharCount propriedade, que retorna o número máximo possível de caracteres que podem fallback ajuste perfeita, substituição ou exceção retorno para substituir um único caractere. Para uma exceção personalizada fallback, seu valor é zero.
O EncoderFallback.CreateFallbackBuffer() ou DecoderFallback.CreateFallbackBuffer() método, que retorna o personalizado EncoderFallbackBuffer ou DecoderFallbackBuffer de implementação. O método é chamado pelo codificador quando encontra o primeiro caractere que não é possível codificar com êxito, ou pelo decodificador quando encontra o primeiro byte que não é possível decodificar com êxito.
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:
O EncoderFallbackBuffer.Fallback() ou DecoderFallbackBuffer.Fallback método. EncoderFallbackBuffer.Fallback()é chamado pelo codificador para fornecer informações sobre o caractere que ele não é possível codificar o buffer de fallback. Como o caractere a ser codificado pode ser um par substituto, este método está sobrecarregado. Uma sobrecarga é passada o caractere a ser codificado e seu índice na string. A segunda sobrecarga é passada alta e baixa surrogate juntamente com seu índice na string. O DecoderFallbackBuffer.Fallback método é chamado pelo decodificador para fornecer informações sobre os bytes que ele não é possível decodificar o buffer de fallback. Esse método é passado a uma matriz de bytes que não é possível decodificar, juntamente com o índice do primeiro byte. O método de retorno deve retornar true se o buffer de fallback pode fornecer um melhor ajuste ou caractere de substituição ou caracteres; Caso contrário, ele deverá retornar false. Uma exceção fallback, o método de retorno deve acionar uma exceção.
O EncoderFallbackBuffer.GetNextChar() ou DecoderFallbackBuffer.GetNextChar() método, que é chamado repetidamente pelo codificador ou decodificador para obter o próximo caractere do buffer de fallback. Quando todos os caracteres de fallback foram retornados, o método deve retornar a U + 0000.
O EncoderFallbackBuffer.Remaining ou DecoderFallbackBuffer.Remaining propriedade, que retorna o número de caracteres restantes no buffer de fallback.
O EncoderFallbackBuffer.MovePrevious() ou DecoderFallbackBuffer.MovePrevious() método, que move a posição atual no buffer de fallback para o caractere anterior.
O EncoderFallbackBuffer.Reset() ou DecoderFallbackBuffer.Reset() método, que reinicializa o buffer de fallback.
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
Outros recursos
Histórico de alterações
Date |
History |
Motivo |
---|---|---|
Outubro de 2010 |
Revisado exaustivamente. |
Aprimoramento de informações. |