Använda teckenkodningsklasser i .NET
Den här artikeln beskriver hur du använder de klasser som .NET tillhandahåller för kodning och avkodning av text med hjälp av olika kodningsscheman. Anvisningarna förutsätter att du har läst Introduktion till teckenkodning i .NET.
Kodare och avkodare
.NET tillhandahåller kodningsklasser som kodar och avkodar text med hjälp av olika kodningssystem. Klassen beskriver till exempel UTF8Encoding reglerna för kodning till och avkodning från UTF-8. .NET använder UTF-16-kodning (representeras av UnicodeEncoding klassen) för string
instanser. Kodare och avkodare är tillgängliga för andra kodningsscheman.
Kodning och avkodning kan också innehålla validering. Klassen kontrollerar till exempel UnicodeEncoding alla char
instanser i surrogatintervallet för att se till att de är i giltiga surrogatpar. En reservstrategi avgör hur en kodare hanterar ogiltiga tecken eller hur en avkodare hanterar ogiltiga byte.
Varning
Med .NET-kodningsklasser kan du lagra och konvertera teckendata. De bör inte användas för att lagra binära data i strängform. Beroende på vilken kodning som används kan konvertering av binära data till strängformat med kodningsklasserna medföra oväntat beteende och generera felaktiga eller skadade data. Om du vill konvertera binära data till ett strängformulär använder du Convert.ToBase64String metoden .
Alla teckenkodningsklasser i .NET ärver från System.Text.Encoding klassen, vilket är en abstrakt klass som definierar de funktioner som är gemensamma för alla teckenkodningar. Om du vill komma åt de enskilda kodningsobjekten som implementeras i .NET gör du följande:
Använd de statiska egenskaperna för Encoding klassen, som returnerar objekt som representerar standardteckenkodningarna som är tillgängliga i .NET (ASCII, UTF-7, UTF-8, UTF-16 och UTF-32). Egenskapen Encoding.Unicode returnerar till exempel ett UnicodeEncoding objekt. Varje objekt använder ersättningsåterställning för att hantera strängar som det inte kan koda och byte som det inte kan avkoda. Mer information finns i Ersättningsåterställning.
Anropa kodningens klasskonstruktor. Objekt för ASCII-, UTF-7-, UTF-8-, UTF-16- och UTF-32-kodningar kan instansieras på det här sättet. Som standard använder varje objekt ersättningsåterställning för att hantera strängar som det inte kan koda och byte som det inte kan avkoda, men du kan ange att ett undantag ska genereras i stället. Mer information finns i Reserv för ersättning och Undantagsåterställning.
Encoding(Int32) Anropa konstruktorn och skicka det ett heltal som representerar kodningen. Standardkodningsobjekt använder ersättningsåterställning, kodsida och DBCS-kodningsobjekt (Double Byte Character Set) använder bästa möjliga återställning för att hantera strängar som de inte kan koda och byte som de inte kan avkoda. Mer information finns i Best-fit reserv.
Encoding.GetEncoding Anropa metoden, som returnerar valfri standard-, kodsida eller DBCS-kodning som är tillgänglig i .NET. Med överlagringar kan du ange ett reservobjekt för både kodaren och avkodaren.
Du kan hämta information om alla kodningar som är tillgängliga i .NET genom att anropa Encoding.GetEncodings metoden. .NET stöder teckenkodningsscheman som anges i följande tabell.
Kodningsklass | beskrivning |
---|---|
ASCII | Kodar ett begränsat antal tecken med hjälp av de lägre sju bitarna av en byte. Eftersom den här kodningen endast stöder teckenvärden från U+0000 och med U+007F är den i de flesta fall otillräcklig för internationaliserade program. |
UTF-7 | Representerar tecken som sekvenser med 7-bitars ASCII-tecken. Unicode-tecken som inte är ASCII representeras av en escape-sekvens med ASCII-tecken. UTF-7 stöder protokoll som e-post och diskussionsgrupp. UTF-7 är dock inte särskilt säkert eller robust. I vissa fall kan en ändring av en bit radikalt ändra tolkningen av en hel UTF-7-sträng. I andra fall kan olika UTF-7-strängar koda samma text. För sekvenser som innehåller icke-ASCII-tecken kräver UTF-7 mer utrymme än UTF-8, och kodning/avkodning är långsammare. Därför bör du använda UTF-8 i stället för UTF-7 om möjligt. |
UTF-8 | Representerar varje Unicode-kodpunkt som en sekvens på en till fyra byte. UTF-8 stöder 8-bitars datastorlekar och fungerar bra med många befintliga operativsystem. FÖR ASCII-teckenintervallet är UTF-8 identiskt med ASCII-kodning och tillåter en bredare uppsättning tecken. Men för CJK-skript (chinese-japanese-korean) kan UTF-8 kräva tre byte för varje tecken och kan orsaka större datastorlekar än UTF-16. Ibland motiverar mängden ASCII-data, till exempel HTML-taggar, den ökade storleken för CJK-intervallet. |
UTF-16 | Representerar varje Unicode-kodpunkt som en sekvens med ett eller två 16-bitars heltal. De vanligaste Unicode-tecknen kräver bara en UTF-16-kodpunkt, även om Unicode-tilläggstecken (U+10000 och senare) kräver två UTF-16 surrogatkodpunkter. Både småsluts- och storslutsbytebeställningar stöds. UTF-16-kodning används av den vanliga språkkörningen för att representera Char och String värden, och den används av Windows-operativsystemet för att representera WCHAR värden. |
UTF-32 | Representerar varje Unicode-kodpunkt som ett 32-bitars heltal. Både småsluts- och storslutsbytebeställningar stöds. UTF-32-kodning används när program vill undvika surrogatkodpunktbeteendet för UTF-16-kodning på operativsystem för vilka kodat utrymme är för viktigt. Enstaka tecken som återges på en skärm kan fortfarande kodas med mer än ett UTF-32-tecken. |
ANSI/ISO-kodning | Ger stöd för en mängd olika kodsidor. I Windows-operativsystem används kodsidor för att stödja ett visst språk eller en viss grupp språk. En tabell som visar de kodsidor som stöds av .NET finns i Encoding klassen . Du kan hämta ett kodningsobjekt för en viss kodsida genom att anropa Encoding.GetEncoding(Int32) metoden. En kodsida innehåller 256 kodpunkter och är nollbaserad. På de flesta kodsidor representerar kodpunkterna 0 till 127 ASCII-teckenuppsättningen och kodpunkterna 128 till 255 skiljer sig avsevärt mellan kodsidorna. Kodsidan 1252 innehåller till exempel tecken för latinska skrivsystem, inklusive engelska, tyska och franska. De sista 128 kodpunkterna på kodsidan 1252 innehåller dekortecken. Kodsidan 1253 innehåller teckenkoder som krävs i det grekiska skrivsystemet. De sista 128 kodpunkterna på kodsidan 1253 innehåller de grekiska tecknen. Därför kan ett program som förlitar sig på ANSI-kodsidor inte lagra grekiska och tyska i samma textström om det inte innehåller en identifierare som anger den refererade kodsidan. |
DBCS-kodningar (Double-Byte Character Set) | Stöder språk, till exempel kinesiska, japanska och koreanska, som innehåller mer än 256 tecken. I en DBCS representerar ett par kodpunkter (en dubbel byte) varje tecken. Egenskapen Encoding.IsSingleByte returnerar false för DBCS-kodningar. Du kan hämta ett kodningsobjekt för en viss DBCS genom att anropa Encoding.GetEncoding(Int32) metoden. När ett program hanterar DBCS-data bearbetas det första bytet av ett DBCS-tecken (leadbyte) i kombination med den spårbyte som omedelbart följer den. Eftersom ett enda par kodpunkter med dubbla byte kan representera olika tecken beroende på kodsidan, tillåter det här schemat fortfarande inte kombinationen av två språk, till exempel japanska och kinesiska, i samma dataström. |
Med dessa kodningar kan du arbeta med Unicode-tecken samt med kodningar som oftast används i äldre program. Dessutom kan du skapa en anpassad kodning genom att definiera en klass som härleds från Encoding och åsidosätter dess medlemmar.
Stöd för .NET Core-kodning
Som standard gör .NET Core inga andra kodningar för kodning av kodningar än kodsidan 28591 och Unicode-kodningarna tillgängliga, till exempel UTF-8 och UTF-16. Du kan dock lägga till kodning för kodning av kodningssidor som finns i Windows-standardappar som riktar in sig på .NET i din app. Mer information finns i avsnittet CodePagesEncodingProvider .
Välja en kodningsklass
Om du har möjlighet att välja den kodning som ska användas av ditt program bör du använda en Unicode-kodning, helst antingen UTF8Encoding eller UnicodeEncoding. (.NET stöder också en tredje Unicode-kodning, UTF32Encoding.)
Om du planerar att använda en ASCII-kodning (ASCIIEncoding) väljer du UTF8Encoding i stället. De två kodningarna är identiska för ASCII-teckenuppsättningen, men UTF8Encoding har följande fördelar:
Det kan representera varje Unicode-tecken, medan ASCIIEncoding endast stöder Unicode-teckenvärdena mellan U+0000 och U+007F.
Det ger felidentifiering och bättre säkerhet.
Den har finjusterats för att vara så snabb som möjligt och bör vara snabbare än någon annan kodning. Även för innehåll som är helt ASCII är åtgärder som utförs med UTF8Encoding snabbare än åtgärder som utförs med ASCIIEncoding.
Du bör endast överväga att använda ASCIIEncoding för äldre program. Men även för äldre program UTF8Encoding kan det vara ett bättre val av följande skäl (om du antar standardinställningar):
Om ditt program har innehåll som inte är strikt ASCII och kodar det med ASCIIEncodingkodas varje icke-ASCII-tecken som ett frågetecken (?). Om programmet sedan avkodar dessa data går informationen förlorad.
Om ditt program har innehåll som inte är strikt ASCII och kodar det med UTF8Encoding, verkar resultatet obegripligt om det tolkas som ASCII. Men om programmet sedan använder en UTF-8-avkodare för att avkoda dessa data, utför data en tur och retur-resa.
I ett webbprogram bör tecken som skickas till klienten som svar på en webbbegäran återspegla den kodning som används på klienten. I de flesta fall bör du ange HttpResponse.ContentEncoding egenskapen till det värde som returneras av HttpRequest.ContentEncoding egenskapen för att visa text i den kodning som användaren förväntar sig.
Använda ett kodningsobjekt
En kodare konverterar en sträng med tecken (oftast Unicode-tecken) till dess numeriska motsvarighet (byte). Du kan till exempel använda en ASCII-kodare för att konvertera Unicode-tecken till ASCII så att de kan visas i konsolen. Om du vill utföra konverteringen anropar Encoding.GetBytes du metoden. Om du vill ta reda på hur många byte som behövs för att lagra kodade tecken innan du utför kodningen kan du anropa GetByteCount metoden.
I följande exempel används en matris med en enda byte för att koda strängar i två separata åtgärder. Det upprätthåller ett index som anger startpositionen i bytematrisen för nästa uppsättning ASCII-kodade byte. Den anropar ASCIIEncoding.GetByteCount(String) metoden för att säkerställa att bytematrisen är tillräckligt stor för att rymma den kodade strängen. Sedan anropas ASCIIEncoding.GetBytes(String, Int32, Int32, Byte[], Int32) metoden för att koda tecknen i strängen.
using System;
using System.Text;
public class Example
{
public static void Main()
{
string[] strings= { "This is the first sentence. ",
"This is the second sentence. " };
Encoding asciiEncoding = Encoding.ASCII;
// Create array of adequate size.
byte[] bytes = new byte[49];
// Create index for current position of array.
int index = 0;
Console.WriteLine("Strings to encode:");
foreach (var stringValue in strings) {
Console.WriteLine(" {0}", stringValue);
int count = asciiEncoding.GetByteCount(stringValue);
if (count + index >= bytes.Length)
Array.Resize(ref bytes, bytes.Length + 50);
int written = asciiEncoding.GetBytes(stringValue, 0,
stringValue.Length,
bytes, index);
index = index + written;
}
Console.WriteLine("\nEncoded bytes:");
Console.WriteLine("{0}", ShowByteValues(bytes, index));
Console.WriteLine();
// Decode Unicode byte array to a string.
string newString = asciiEncoding.GetString(bytes, 0, index);
Console.WriteLine("Decoded: {0}", newString);
}
private static string ShowByteValues(byte[] bytes, int last )
{
string returnString = " ";
for (int ctr = 0; ctr <= last - 1; ctr++) {
if (ctr % 20 == 0)
returnString += "\n ";
returnString += String.Format("{0:X2} ", bytes[ctr]);
}
return returnString;
}
}
// The example displays the following output:
// Strings to encode:
// This is the first sentence.
// This is the second sentence.
//
// Encoded bytes:
//
// 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
// 6E 74 65 6E 63 65 2E 20 54 68 69 73 20 69 73 20 74 68 65 20
// 73 65 63 6F 6E 64 20 73 65 6E 74 65 6E 63 65 2E 20
//
// Decoded: This is the first sentence. This is the second sentence.
Imports System.Text
Module Example
Public Sub Main()
Dim strings() As String = {"This is the first sentence. ",
"This is the second sentence. "}
Dim asciiEncoding As Encoding = Encoding.ASCII
' Create array of adequate size.
Dim bytes(50) As Byte
' Create index for current position of array.
Dim index As Integer = 0
Console.WriteLine("Strings to encode:")
For Each stringValue In strings
Console.WriteLine(" {0}", stringValue)
Dim count As Integer = asciiEncoding.GetByteCount(stringValue)
If count + index >= bytes.Length Then
Array.Resize(bytes, bytes.Length + 50)
End If
Dim written As Integer = asciiEncoding.GetBytes(stringValue, 0,
stringValue.Length,
bytes, index)
index = index + written
Next
Console.WriteLine()
Console.WriteLine("Encoded bytes:")
Console.WriteLine("{0}", ShowByteValues(bytes, index))
Console.WriteLine()
' Decode Unicode byte array to a string.
Dim newString As String = asciiEncoding.GetString(bytes, 0, index)
Console.WriteLine("Decoded: {0}", newString)
End Sub
Private Function ShowByteValues(bytes As Byte(), last As Integer) As String
Dim returnString As String = " "
For ctr As Integer = 0 To last - 1
If ctr Mod 20 = 0 Then returnString += vbCrLf + " "
returnString += String.Format("{0:X2} ", bytes(ctr))
Next
Return returnString
End Function
End Module
' The example displays the following output:
' Strings to encode:
' This is the first sentence.
' This is the second sentence.
'
' Encoded bytes:
'
' 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
' 6E 74 65 6E 63 65 2E 20 54 68 69 73 20 69 73 20 74 68 65 20
' 73 65 63 6F 6E 64 20 73 65 6E 74 65 6E 63 65 2E 20
'
' Decoded: This is the first sentence. This is the second sentence.
En avkodare konverterar en bytematris som återspeglar en viss teckenkodning till en uppsättning tecken, antingen i en teckenmatris eller i en sträng. Om du vill avkoda en bytematris till en teckenmatris anropar Encoding.GetChars du metoden. Om du vill avkoda en bytematris till en sträng anropar GetString du metoden. Om du vill fastställa hur många tecken som behövs för att lagra de avkodade byteen innan du utför avkodningen kan du anropa GetCharCount metoden.
I följande exempel kodas tre strängar och avkodas sedan till en enda matris med tecken. Det upprätthåller ett index som anger startpositionen i teckenmatrisen för nästa uppsättning avkodade tecken. Den anropar GetCharCount metoden för att säkerställa att teckenmatrisen är tillräckligt stor för att rymma alla avkodade tecken. Sedan anropas ASCIIEncoding.GetChars(Byte[], Int32, Int32, Char[], Int32) metoden för att avkoda bytematrisen.
using System;
using System.Text;
public class Example
{
public static void Main()
{
string[] strings = { "This is the first sentence. ",
"This is the second sentence. ",
"This is the third sentence. " };
Encoding asciiEncoding = Encoding.ASCII;
// Array to hold encoded bytes.
byte[] bytes;
// Array to hold decoded characters.
char[] chars = new char[50];
// Create index for current position of character array.
int index = 0;
foreach (var stringValue in strings) {
Console.WriteLine("String to Encode: {0}", stringValue);
// Encode the string to a byte array.
bytes = asciiEncoding.GetBytes(stringValue);
// Display the encoded bytes.
Console.Write("Encoded bytes: ");
for (int ctr = 0; ctr < bytes.Length; ctr++)
Console.Write(" {0}{1:X2}",
ctr % 20 == 0 ? Environment.NewLine : "",
bytes[ctr]);
Console.WriteLine();
// Decode the bytes to a single character array.
int count = asciiEncoding.GetCharCount(bytes);
if (count + index >= chars.Length)
Array.Resize(ref chars, chars.Length + 50);
int written = asciiEncoding.GetChars(bytes, 0,
bytes.Length,
chars, index);
index = index + written;
Console.WriteLine();
}
// Instantiate a single string containing the characters.
string decodedString = new string(chars, 0, index - 1);
Console.WriteLine("Decoded string: ");
Console.WriteLine(decodedString);
}
}
// The example displays the following output:
// String to Encode: This is the first sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
// 6E 74 65 6E 63 65 2E 20
//
// String to Encode: This is the second sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 73 65 63 6F 6E 64 20 73
// 65 6E 74 65 6E 63 65 2E 20
//
// String to Encode: This is the third sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 74 68 69 72 64 20 73 65
// 6E 74 65 6E 63 65 2E 20
//
// Decoded string:
// This is the first sentence. This is the second sentence. This is the third sentence.
Imports System.Text
Module Example
Public Sub Main()
Dim strings() As String = {"This is the first sentence. ",
"This is the second sentence. ",
"This is the third sentence. "}
Dim asciiEncoding As Encoding = Encoding.ASCII
' Array to hold encoded bytes.
Dim bytes() As Byte
' Array to hold decoded characters.
Dim chars(50) As Char
' Create index for current position of character array.
Dim index As Integer
For Each stringValue In strings
Console.WriteLine("String to Encode: {0}", stringValue)
' Encode the string to a byte array.
bytes = asciiEncoding.GetBytes(stringValue)
' Display the encoded bytes.
Console.Write("Encoded bytes: ")
For ctr As Integer = 0 To bytes.Length - 1
Console.Write(" {0}{1:X2}", If(ctr Mod 20 = 0, vbCrLf, ""),
bytes(ctr))
Next
Console.WriteLine()
' Decode the bytes to a single character array.
Dim count As Integer = asciiEncoding.GetCharCount(bytes)
If count + index >= chars.Length Then
Array.Resize(chars, chars.Length + 50)
End If
Dim written As Integer = asciiEncoding.GetChars(bytes, 0,
bytes.Length,
chars, index)
index = index + written
Console.WriteLine()
Next
' Instantiate a single string containing the characters.
Dim decodedString As New String(chars, 0, index - 1)
Console.WriteLine("Decoded string: ")
Console.WriteLine(decodedString)
End Sub
End Module
' The example displays the following output:
' String to Encode: This is the first sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
' 6E 74 65 6E 63 65 2E 20
'
' String to Encode: This is the second sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 73 65 63 6F 6E 64 20 73
' 65 6E 74 65 6E 63 65 2E 20
'
' String to Encode: This is the third sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 74 68 69 72 64 20 73 65
' 6E 74 65 6E 63 65 2E 20
'
' Decoded string:
' This is the first sentence. This is the second sentence. This is the third sentence.
Kodnings- och avkodningsmetoderna för en klass som härleds från Encoding är utformade för att fungera med en fullständig uppsättning data, det vill säga att alla data som ska kodas eller avkodas tillhandahålls i ett enda metodanrop. I vissa fall är dock data tillgängliga i en dataström, och de data som ska kodas eller avkodas kan endast vara tillgängliga från separata läsåtgärder. Detta kräver att kodnings- eller avkodningsåtgärden kommer ihåg alla sparade tillstånd från dess tidigare anrop. Metoder för klasser som härleds från Encoder och Decoder kan hantera kodnings- och avkodningsåtgärder som omfattar flera metodanrop.
Ett Encoder objekt för en viss kodning är tillgängligt från den kodningens Encoding.GetEncoder egenskap. Ett Decoder objekt för en viss kodning är tillgängligt från den kodningens Encoding.GetDecoder egenskap. Observera att klasser som härleds från Decoder innehåller en Decoder.GetChars metod för avkodningsåtgärder, men att de inte har någon metod som motsvarar Encoding.GetString.
I följande exempel visas skillnaden mellan att använda Encoding.GetString metoderna och Decoder.GetChars för att avkoda en Unicode-bytematris. Exemplet kodar en sträng som innehåller vissa Unicode-tecken till en fil och använder sedan de två avkodningsmetoderna för att avkoda dem tio byte i taget. Eftersom ett surrogatpar förekommer i den tionde och elfte byteen avkodas det i separata metodanrop. Som utdata visar Encoding.GetString kan metoden inte avkoda byteen korrekt och ersätter dem i stället med U+FFFD (REPLACEMENT CHARACTER). Å Decoder.GetChars andra sidan kan metoden avkoda bytematrisen för att hämta den ursprungliga strängen.
using System;
using System.IO;
using System.Text;
public class Example
{
public static void Main()
{
// Use default replacement fallback for invalid encoding.
UnicodeEncoding enc = new UnicodeEncoding(true, false, false);
// Define a string with various Unicode characters.
string str1 = "AB YZ 19 \uD800\udc05 \u00e4";
str1 += "Unicode characters. \u00a9 \u010C s \u0062\u0308";
Console.WriteLine("Created original string...\n");
// Convert string to byte array.
byte[] bytes = enc.GetBytes(str1);
FileStream fs = File.Create(@".\characters.bin");
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes);
bw.Close();
// Read bytes from file.
FileStream fsIn = File.OpenRead(@".\characters.bin");
BinaryReader br = new BinaryReader(fsIn);
const int count = 10; // Number of bytes to read at a time.
byte[] bytesRead = new byte[10]; // Buffer (byte array).
int read; // Number of bytes actually read.
string str2 = String.Empty; // Decoded string.
// Try using Encoding object for all operations.
do {
read = br.Read(bytesRead, 0, count);
str2 += enc.GetString(bytesRead, 0, read);
} while (read == count);
br.Close();
Console.WriteLine("Decoded string using UnicodeEncoding.GetString()...");
CompareForEquality(str1, str2);
Console.WriteLine();
// Use Decoder for all operations.
fsIn = File.OpenRead(@".\characters.bin");
br = new BinaryReader(fsIn);
Decoder decoder = enc.GetDecoder();
char[] chars = new char[50];
int index = 0; // Next character to write in array.
int written = 0; // Number of chars written to array.
do {
read = br.Read(bytesRead, 0, count);
if (index + decoder.GetCharCount(bytesRead, 0, read) - 1 >= chars.Length)
Array.Resize(ref chars, chars.Length + 50);
written = decoder.GetChars(bytesRead, 0, read, chars, index);
index += written;
} while (read == count);
br.Close();
// Instantiate a string with the decoded characters.
string str3 = new String(chars, 0, index);
Console.WriteLine("Decoded string using UnicodeEncoding.Decoder.GetString()...");
CompareForEquality(str1, str3);
}
private static void CompareForEquality(string original, string decoded)
{
bool result = original.Equals(decoded);
Console.WriteLine("original = decoded: {0}",
original.Equals(decoded, StringComparison.Ordinal));
if (! result) {
Console.WriteLine("Code points in original string:");
foreach (var ch in original)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
Console.WriteLine("Code points in decoded string:");
foreach (var ch in decoded)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Created original string...
//
// Decoded string using UnicodeEncoding.GetString()...
// original = decoded: False
// Code points in original string:
// 0041 0042 0020 0059 005A 0020 0031 0039 0020 D800 DC05 0020 00E4 0055 006E 0069 0063 006F
// 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
// 0020 0073 0020 0062 0308
// Code points in decoded string:
// 0041 0042 0020 0059 005A 0020 0031 0039 0020 FFFD FFFD 0020 00E4 0055 006E 0069 0063 006F
// 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
// 0020 0073 0020 0062 0308
//
// Decoded string using UnicodeEncoding.Decoder.GetString()...
// original = decoded: True
Imports System.IO
Imports System.Text
Module Example
Public Sub Main()
' Use default replacement fallback for invalid encoding.
Dim enc As New UnicodeEncoding(True, False, False)
' Define a string with various Unicode characters.
Dim str1 As String = String.Format("AB YZ 19 {0}{1} {2}",
ChrW(&hD800), ChrW(&hDC05), ChrW(&h00e4))
str1 += String.Format("Unicode characters. {0} {1} s {2}{3}",
ChrW(&h00a9), ChrW(&h010C), ChrW(&h0062), ChrW(&h0308))
Console.WriteLine("Created original string...")
Console.WriteLine()
' Convert string to byte array.
Dim bytes() As Byte = enc.GetBytes(str1)
Dim fs As FileStream = File.Create(".\characters.bin")
Dim bw As New BinaryWriter(fs)
bw.Write(bytes)
bw.Close()
' Read bytes from file.
Dim fsIn As FileStream = File.OpenRead(".\characters.bin")
Dim br As New BinaryReader(fsIn)
Const count As Integer = 10 ' Number of bytes to read at a time.
Dim bytesRead(9) As Byte ' Buffer (byte array).
Dim read As Integer ' Number of bytes actually read.
Dim str2 As String = "" ' Decoded string.
' Try using Encoding object for all operations.
Do
read = br.Read(bytesRead, 0, count)
str2 += enc.GetString(bytesRead, 0, read)
Loop While read = count
br.Close()
Console.WriteLine("Decoded string using UnicodeEncoding.GetString()...")
CompareForEquality(str1, str2)
Console.WriteLine()
' Use Decoder for all operations.
fsIn = File.OpenRead(".\characters.bin")
br = New BinaryReader(fsIn)
Dim decoder As Decoder = enc.GetDecoder()
Dim chars(50) As Char
Dim index As Integer = 0 ' Next character to write in array.
Dim written As Integer = 0 ' Number of chars written to array.
Do
read = br.Read(bytesRead, 0, count)
If index + decoder.GetCharCount(bytesRead, 0, read) - 1 >= chars.Length Then
Array.Resize(chars, chars.Length + 50)
End If
written = decoder.GetChars(bytesRead, 0, read, chars, index)
index += written
Loop While read = count
br.Close()
' Instantiate a string with the decoded characters.
Dim str3 As New String(chars, 0, index)
Console.WriteLine("Decoded string using UnicodeEncoding.Decoder.GetString()...")
CompareForEquality(str1, str3)
End Sub
Private Sub CompareForEquality(original As String, decoded As String)
Dim result As Boolean = original.Equals(decoded)
Console.WriteLine("original = decoded: {0}",
original.Equals(decoded, StringComparison.Ordinal))
If Not result Then
Console.WriteLine("Code points in original string:")
For Each ch In original
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine("Code points in decoded string:")
For Each ch In decoded
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Created original string...
'
' Decoded string using UnicodeEncoding.GetString()...
' original = decoded: False
' Code points in original string:
' 0041 0042 0020 0059 005A 0020 0031 0039 0020 D800 DC05 0020 00E4 0055 006E 0069 0063 006F
' 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
' 0020 0073 0020 0062 0308
' Code points in decoded string:
' 0041 0042 0020 0059 005A 0020 0031 0039 0020 FFFD FFFD 0020 00E4 0055 006E 0069 0063 006F
' 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
' 0020 0073 0020 0062 0308
'
' Decoded string using UnicodeEncoding.Decoder.GetString()...
' original = decoded: True
Välja en reservstrategi
När en metod försöker koda eller avkoda ett tecken men det inte finns någon mappning måste den implementera en reservstrategi som avgör hur den misslyckade mappningen ska hanteras. Det finns tre typer av reservstrategier:
Best-fit reserv
Reserv för ersättning
Undantagsåterställning
Viktigt!
De vanligaste problemen med kodningsåtgärder uppstår när ett Unicode-tecken inte kan mappas till en viss kodning av kodningssidor. De vanligaste problemen med avkodningsåtgärder uppstår när ogiltiga bytesekvenser inte kan översättas till giltiga Unicode-tecken. Därför bör du veta vilken reservstrategi ett visst kodningsobjekt använder. När det är möjligt bör du ange den återställningsstrategi som används av ett kodningsobjekt när du instansierar objektet.
Best-Fit Fallback
När ett tecken inte har någon exakt matchning i målkodningen kan kodaren försöka mappa det till ett liknande tecken. (Bästa möjliga reserv är främst en kodning snarare än ett avkodningsproblem. Det finns mycket få kodsidor som innehåller tecken som inte kan mappas till Unicode.) Återställning efter bästa passform är standardinställningen för kodsidan och teckenuppsättningskodningar med dubbla byte som hämtas av Encoding.GetEncoding(Int32) överlagringarna och Encoding.GetEncoding(String) .
Kommentar
I teorin stöder Unicode-kodningsklasserna i .NET (UTF8Encoding, UnicodeEncoding, och UTF32Encoding) varje tecken i varje teckenuppsättning, så att de kan användas för att eliminera problem med bästa möjliga återställning.
Strategier som passar bäst varierar för olika kodsidor. För vissa kodsidor mappas till exempel latinska tecken med full bredd till vanliga latinska tecken med halv bredd. För andra kodsidor görs inte den här mappningen. Även under en aggressiv strategi för bästa passform finns det ingen tänkbar passform för vissa karaktärer i vissa kodningar. En kinesisk ideografi har till exempel ingen rimlig mappning till kodsidan 1252. I det här fallet används en ersättningssträng. Som standard är den här strängen bara ett enda FRÅGETECKEN (U+003F).
Kommentar
Strategier som passar bäst dokumenteras inte i detalj. Flera kodsidor dokumenteras dock på Unicode Consortiums webbplats. Läs readme.txt filen i mappen för en beskrivning av hur du tolkar mappningsfilerna.
I följande exempel används kodsidan 1252 (Windows-kodsidan för västeuropeiska språk) för att illustrera bästa möjliga mappning och dess nackdelar. Metoden Encoding.GetEncoding(Int32) används för att hämta ett kodningsobjekt för kodningssidan 1252. Som standard använder den en mappning som passar bäst för Unicode-tecken som den inte stöder. Exemplet instansierar en sträng som innehåller tre icke-ASCII-tecken – CIRCLED LATIN CAPITAL LETTER S (U+24C8), SUPERSCRIPT FIVE (U+2075) och INFINITY (U+221E) – avgränsade med blanksteg. Som utdata från exemplet visar, när strängen är kodad, ersätts de tre ursprungliga icke-blankstegsteckenen med FRÅGETECKEN (U+003F), DIGIT FIVE (U+0035) och DIGIT EIGHT (U+0038). DIGIT EIGHT är en särskilt dålig ersättning för DET OÄNDLIGT tecken som inte stöds, och FRÅGETECKEN anger att ingen mappning var tillgänglig för det ursprungliga tecknet.
using System;
using System.Text;
public class Example
{
public static void Main()
{
// Get an encoding for code page 1252 (Western Europe character set).
Encoding cp1252 = Encoding.GetEncoding(1252);
// Define and display a string.
string str = "\u24c8 \u2075 \u221e";
Console.WriteLine("Original string: " + str);
Console.Write("Code points in string: ");
foreach (var ch in str)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine("\n");
// Encode a Unicode string.
Byte[] bytes = cp1252.GetBytes(str);
Console.Write("Encoded bytes: ");
foreach (byte byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");
// Decode the string.
string str2 = cp1252.GetString(bytes);
Console.WriteLine("String round-tripped: {0}", str.Equals(str2));
if (! str.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
}
}
}
// The example displays the following output:
// Original string: Ⓢ ⁵ ∞
// Code points in string: 24C8 0020 2075 0020 221E
//
// Encoded bytes: 3F 20 35 20 38
//
// String round-tripped: False
// ? 5 8
// 003F 0020 0035 0020 0038
Imports System.Text
Module Example
Public Sub Main()
' Get an encoding for code page 1252 (Western Europe character set).
Dim cp1252 As Encoding = Encoding.GetEncoding(1252)
' Define and display a string.
Dim str As String = String.Format("{0} {1} {2}", ChrW(&h24c8), ChrW(&H2075), ChrW(&h221E))
Console.WriteLine("Original string: " + str)
Console.Write("Code points in string: ")
For Each ch In str
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()
' Encode a Unicode string.
Dim bytes() As Byte = cp1252.GetBytes(str)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()
' Decode the string.
Dim str2 As String = cp1252.GetString(bytes)
Console.WriteLine("String round-tripped: {0}", str.Equals(str2))
If Not str.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
End If
End Sub
End Module
' The example displays the following output:
' Original string: Ⓢ ⁵ ∞
' Code points in string: 24C8 0020 2075 0020 221E
'
' Encoded bytes: 3F 20 35 20 38
'
' String round-tripped: False
' ? 5 8
' 003F 0020 0035 0020 0038
Bästa möjliga mappning är standardbeteendet för ett Encoding objekt som kodar Unicode-data till kodsidesdata, och det finns äldre program som förlitar sig på det här beteendet. De flesta nya program bör dock undvika bästa möjliga beteende av säkerhetsskäl. Till exempel bör program inte placera ett domännamn via en bäst anpassad kodning.
Kommentar
Du kan också implementera en anpassad reservmappning med bästa passform för en kodning. Mer information finns i avsnittet Implementera en anpassad återställningsstrategi .
Om bästa möjliga återställning är standard för ett kodningsobjekt kan du välja en annan återställningsstrategi när du hämtar ett Encoding objekt genom att anropa Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) eller Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) överbelasta. Följande avsnitt innehåller ett exempel som ersätter varje tecken som inte kan mappas till kodsidan 1252 med en asterisk (*).
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding cp1252r = Encoding.GetEncoding(1252,
new EncoderReplacementFallback("*"),
new DecoderReplacementFallback("*"));
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
byte[] bytes = cp1252r.GetBytes(str1);
string str2 = cp1252r.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
// Round-trip: False
// * * *
// 002A 0020 002A 0020 002A
Imports System.Text
Module Example
Public Sub Main()
Dim cp1252r As Encoding = Encoding.GetEncoding(1252,
New EncoderReplacementFallback("*"),
New DecoderReplacementFallback("*"))
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Dim bytes() As Byte = cp1252r.GetBytes(str1)
Dim str2 As String = cp1252r.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
' Round-trip: False
' * * *
' 002A 0020 002A 0020 002A
Reserv för ersättning
När ett tecken inte har någon exakt matchning i målschemat, men det inte finns något lämpligt tecken som det kan mappas till, kan programmet ange ett ersättningstecken eller en sträng. Detta är standardbeteendet för Unicode-avkodaren, som ersätter alla två bytessekvenser som inte kan avkodas med REPLACEMENT_CHARACTER (U+FFFD). Det är också standardbeteendet för ASCIIEncoding klassen, som ersätter varje tecken som det inte kan koda eller avkoda med ett frågetecken. I följande exempel visas teckenersättning för Unicode-strängen från föregående exempel. Som utdata visar ersätts varje tecken som inte kan avkodas till ett ASCII-bytevärde av 0x3F, vilket är ASCII-koden för ett frågetecken.
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding enc = Encoding.ASCII;
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine("\n");
// Encode the original string using the ASCII encoder.
byte[] bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");
// Decode the ASCII bytes.
string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
//
// Encoded bytes: 3F 20 3F 20 3F
//
// Round-trip: False
// ? ? ?
// 003F 0020 003F 0020 003F
Imports System.Text
Module Example
Public Sub Main()
Dim enc As Encoding = Encoding.Ascii
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()
' Encode the original string using the ASCII encoder.
Dim bytes() As Byte = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()
' Decode the ASCII bytes.
Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
'
' Encoded bytes: 3F 20 3F 20 3F
'
' Round-trip: False
' ? ? ?
' 003F 0020 003F 0020 003F
.NET innehåller klasserna EncoderReplacementFallback och DecoderReplacementFallback som ersätter en ersättningssträng om ett tecken inte mappas exakt i en kodnings- eller avkodningsåtgärd. Som standard är den här ersättningssträngen ett frågetecken, men du kan anropa en klasskonstruktoröverlagring för att välja en annan sträng. Ersättningssträngen är vanligtvis ett enda tecken, även om detta inte är ett krav. I följande exempel ändras beteendet för kodningssidan 1252 genom att instansiera ett EncoderReplacementFallback objekt som använder en asterisk (*) som ersättningssträng.
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding cp1252r = Encoding.GetEncoding(1252,
new EncoderReplacementFallback("*"),
new DecoderReplacementFallback("*"));
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
byte[] bytes = cp1252r.GetBytes(str1);
string str2 = cp1252r.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
// Round-trip: False
// * * *
// 002A 0020 002A 0020 002A
Imports System.Text
Module Example
Public Sub Main()
Dim cp1252r As Encoding = Encoding.GetEncoding(1252,
New EncoderReplacementFallback("*"),
New DecoderReplacementFallback("*"))
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Dim bytes() As Byte = cp1252r.GetBytes(str1)
Dim str2 As String = cp1252r.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
' Round-trip: False
' * * *
' 002A 0020 002A 0020 002A
Kommentar
Du kan också implementera en ersättningsklass för en kodning. Mer information finns i avsnittet Implementera en anpassad återställningsstrategi .
Förutom FRÅGETECKEN (U+003F) används Unicode REPLACEMENT CHARACTER (U+FFFD) ofta som en ersättningssträng, särskilt vid avkodning av bytesekvenser som inte kan översättas till Unicode-tecken. Du kan dock välja valfri ersättningssträng och den kan innehålla flera tecken.
Undantagsåterställning
I stället för att tillhandahålla en reservdel som passar bäst eller en ersättningssträng kan en kodare utlösa en EncoderFallbackException om den inte kan koda en uppsättning tecken, och en avkodare kan utlösa en DecoderFallbackException om den inte kan avkoda en bytematris. Om du vill utlösa ett undantag i kodnings- och avkodningsåtgärder anger du ett EncoderExceptionFallback objekt respektive ett DecoderExceptionFallback objekt till Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) metoden. I följande exempel visas undantagsåterställning med ASCIIEncoding klassen.
using System;
using System.Text;
public class Example
{
public static void Main()
{
Encoding enc = Encoding.GetEncoding("us-ascii",
new EncoderExceptionFallback(),
new DecoderExceptionFallback());
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine("\n");
// Encode the original string using the ASCII encoder.
byte[] bytes = {};
try {
bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine();
}
catch (EncoderFallbackException e) {
Console.Write("Exception: ");
if (e.IsUnknownSurrogate())
Console.WriteLine("Unable to encode surrogate pair 0x{0:X4} 0x{1:X3} at index {2}.",
Convert.ToUInt16(e.CharUnknownHigh),
Convert.ToUInt16(e.CharUnknownLow),
e.Index);
else
Console.WriteLine("Unable to encode 0x{0:X4} at index {1}.",
Convert.ToUInt16(e.CharUnknown),
e.Index);
return;
}
Console.WriteLine();
// Decode the ASCII bytes.
try {
string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
catch (DecoderFallbackException e) {
Console.Write("Unable to decode byte(s) ");
foreach (byte unknown in e.BytesUnknown)
Console.Write("0x{0:X2} ");
Console.WriteLine("at index {0}", e.Index);
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
//
// Exception: Unable to encode 0x24C8 at index 0.
Imports System.Text
Module Example
Public Sub Main()
Dim enc As Encoding = Encoding.GetEncoding("us-ascii",
New EncoderExceptionFallback(),
New DecoderExceptionFallback())
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))
Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()
' Encode the original string using the ASCII encoder.
Dim bytes() As Byte = {}
Try
bytes = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Catch e As EncoderFallbackException
Console.Write("Exception: ")
If e.IsUnknownSurrogate() Then
Console.WriteLine("Unable to encode surrogate pair 0x{0:X4} 0x{1:X3} at index {2}.",
Convert.ToUInt16(e.CharUnknownHigh),
Convert.ToUInt16(e.CharUnknownLow),
e.Index)
Else
Console.WriteLine("Unable to encode 0x{0:X4} at index {1}.",
Convert.ToUInt16(e.CharUnknown),
e.Index)
End If
Exit Sub
End Try
Console.WriteLine()
' Decode the ASCII bytes.
Try
Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
Catch e As DecoderFallbackException
Console.Write("Unable to decode byte(s) ")
For Each unknown As Byte In e.BytesUnknown
Console.Write("0x{0:X2} ")
Next
Console.WriteLine("at index {0}", e.Index)
End Try
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
'
' Exception: Unable to encode 0x24C8 at index 0.
Kommentar
Du kan också implementera en anpassad undantagshanterare för en kodningsåtgärd. Mer information finns i avsnittet Implementera en anpassad återställningsstrategi .
Objekten EncoderFallbackException och DecoderFallbackException innehåller följande information om villkoret som orsakade undantaget:
Objektet EncoderFallbackException innehåller en IsUnknownSurrogate metod som anger om tecknet eller tecknen som inte kan kodas representerar ett okänt surrogatpar (i vilket fall metoden returnerar
true
) eller ett okänt enskilt tecken (i så fall returnerarfalse
metoden ). Tecknen i surrogatparet är tillgängliga från EncoderFallbackException.CharUnknownHigh egenskaperna och EncoderFallbackException.CharUnknownLow . Det okända enskilda tecknet är tillgängligt från egenskapen EncoderFallbackException.CharUnknown . Egenskapen EncoderFallbackException.Index anger positionen i strängen där det första tecknet som inte kunde kodas hittades.Objektet DecoderFallbackException innehåller en BytesUnknown egenskap som returnerar en matris med byte som inte kan avkodas. Egenskapen DecoderFallbackException.Index anger startpositionen för okända byte.
Även om objekten EncoderFallbackException och DecoderFallbackException ger tillräcklig diagnostisk information om undantaget ger de inte åtkomst till kodnings- eller avkodningsbufferten. Därför tillåter de inte att ogiltiga data ersätts eller korrigeras inom kodnings- eller avkodningsmetoden.
Implementera en anpassad återställningsstrategi
Förutom den mappning som passar bäst som implementeras internt av kodsidor innehåller .NET följande klasser för att implementera en reservstrategi:
Använd EncoderReplacementFallback och EncoderReplacementFallbackBuffer för att ersätta tecken i kodningsåtgärder.
Använd DecoderReplacementFallback och DecoderReplacementFallbackBuffer för att ersätta tecken i avkodningsåtgärder.
Använd EncoderExceptionFallback och EncoderExceptionFallbackBuffer för att generera ett EncoderFallbackException när ett tecken inte kan kodas.
Använd DecoderExceptionFallback och DecoderExceptionFallbackBuffer för att generera en DecoderFallbackException när ett tecken inte kan avkodas.
Dessutom kan du implementera en anpassad lösning som använder återställning efter bästa passform, återställning efter ersättning eller undantagsåterställning genom att följa dessa steg:
Härled en klass från EncoderFallback för kodningsåtgärder och från DecoderFallback för avkodningsåtgärder.
Härled en klass från EncoderFallbackBuffer för kodningsåtgärder och från DecoderFallbackBuffer för avkodningsåtgärder.
För undantagsåterställning, om de fördefinierade EncoderFallbackException klasserna och DecoderFallbackException klasserna inte uppfyller dina behov, härleder du en klass från ett undantagsobjekt som Exception eller ArgumentException.
Härled från EncoderFallback eller DecoderFallback
Om du vill implementera en anpassad återställningslösning måste du skapa en klass som ärver från EncoderFallback för kodningsåtgärder och från DecoderFallback för avkodningsåtgärder. Instanser av dessa klasser skickas till Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) metoden och fungerar som mellanhand mellan kodningsklassen och återställningsimplementeringen.
När du skapar en anpassad reservlösning för en kodare eller avkodare måste du implementera följande medlemmar:
Egenskapen EncoderFallback.MaxCharCount eller DecoderFallback.MaxCharCount , som returnerar det maximala antalet tecken som passar bäst, ersätter eller undantagsåterställning kan returnera för att ersätta ett enda tecken. För en anpassad undantagsåterställning är dess värde noll.
Metoden EncoderFallback.CreateFallbackBuffer eller DecoderFallback.CreateFallbackBuffer som returnerar din anpassade eller DecoderFallbackBuffer implementeringEncoderFallbackBuffer. Metoden anropas av kodaren när den stöter på det första tecknet som inte kan kodas, eller av avkodaren när den stöter på den första byte som den inte kan avkoda.
Härled från EncoderFallbackBuffer eller DecoderFallbackBuffer
Om du vill implementera en anpassad återställningslösning måste du också skapa en klass som ärver från EncoderFallbackBuffer för kodningsåtgärder och från DecoderFallbackBuffer för avkodningsåtgärder. Instanser av dessa klasser returneras med CreateFallbackBuffer metoden EncoderFallback och DecoderFallback klasserna. Metoden EncoderFallback.CreateFallbackBuffer anropas av kodaren när den stöter på det första tecknet som den inte kan koda, och DecoderFallback.CreateFallbackBuffer metoden anropas av avkodaren när den stöter på en eller flera byte som den inte kan avkoda. Klasserna EncoderFallbackBuffer och DecoderFallbackBuffer tillhandahåller reservimplementeringen. Varje instans representerar en buffert som innehåller återställningstecken som ersätter det tecken som inte kan kodas eller bytesekvensen som inte kan avkodas.
När du skapar en anpassad reservlösning för en kodare eller avkodare måste du implementera följande medlemmar:
Eller-metoden EncoderFallbackBuffer.FallbackDecoderFallbackBuffer.Fallback . EncoderFallbackBuffer.Fallback anropas av kodaren för att tillhandahålla reservbufferten med information om det tecken som den inte kan koda. Eftersom tecknet som ska kodas kan vara ett surrogatpar är den här metoden överbelastad. En överlagring skickas det tecken som ska kodas och dess index i strängen. Den andra överlagringen skickas den höga och låga surrogaten tillsammans med dess index i strängen. Metoden DecoderFallbackBuffer.Fallback anropas av avkodaren för att tillhandahålla reservbufferten med information om byte som den inte kan avkoda. Den här metoden skickas en matris med byte som den inte kan avkoda, tillsammans med indexet för den första byte. Återställningsmetoden bör returneras
true
om reservbufferten kan ange ett lämpligt eller ersättningstecken eller tecken. Annars bör den returnerafalse
. För en undantagsåterställning bör återställningsmetoden utlösa ett undantag.Metoden EncoderFallbackBuffer.GetNextChar eller DecoderFallbackBuffer.GetNextChar som anropas upprepade gånger av kodaren eller avkodaren för att hämta nästa tecken från reservbufferten. När alla återställningstecken har returnerats ska metoden returnera U+0000.
Egenskapen EncoderFallbackBuffer.Remaining eller DecoderFallbackBuffer.Remaining som returnerar antalet tecken som finns kvar i reservbufferten.
Metoden EncoderFallbackBuffer.MovePrevious eller DecoderFallbackBuffer.MovePrevious , som flyttar den aktuella positionen i återställningsbufferten till föregående tecken.
Metoden EncoderFallbackBuffer.Reset eller DecoderFallbackBuffer.Reset som initierar återställningsbufferten igen.
Om återställningsimplementeringen är en reservdel som passar bäst eller en ersättningsåterställning, kommer klasserna från EncoderFallbackBuffer och DecoderFallbackBuffer underhåller även två privata instansfält: det exakta antalet tecken i bufferten och indexet för nästa tecken i bufferten som ska returneras.
Ett Exempel på encoderFallback
I ett tidigare exempel användes ersättningsåterställning för att ersätta Unicode-tecken som inte motsvarade ASCII-tecken med en asterisk (*). I följande exempel används en anpassad reservimplementering med bästa passform i stället för att ge en bättre mappning av icke-ASCII-tecken.
Följande kod definierar en klass med namnet CustomMapper
som härleds från EncoderFallback för att hantera den bästa mappningen av icke-ASCII-tecken. Dess CreateFallbackBuffer
metod returnerar ett CustomMapperFallbackBuffer
objekt som tillhandahåller implementeringen EncoderFallbackBuffer . Klassen CustomMapper
använder ett Dictionary<TKey,TValue> objekt för att lagra mappningar av Unicode-tecken som inte stöds (nyckelvärdet) och deras motsvarande 8-bitarstecken (som lagras i två på varandra följande byte i ett 64-bitars heltal). För att göra den här mappningen tillgänglig för återställningsbufferten skickas instansen CustomMapper
som en parameter till CustomMapperFallbackBuffer
klasskonstruktorn. Eftersom den längsta mappningen är strängen "INF" för Unicode-tecknet U+221E returnerar MaxCharCount
egenskapen 3.
public class CustomMapper : EncoderFallback
{
public string DefaultString;
internal Dictionary<ushort, ulong> mapping;
public CustomMapper() : this("*")
{
}
public CustomMapper(string defaultString)
{
this.DefaultString = defaultString;
// Create table of mappings
mapping = new Dictionary<ushort, ulong>();
mapping.Add(0x24C8, 0x53);
mapping.Add(0x2075, 0x35);
mapping.Add(0x221E, 0x49004E0046);
}
public override EncoderFallbackBuffer CreateFallbackBuffer()
{
return new CustomMapperFallbackBuffer(this);
}
public override int MaxCharCount
{
get { return 3; }
}
}
Public Class CustomMapper : Inherits EncoderFallback
Public DefaultString As String
Friend mapping As Dictionary(Of UShort, ULong)
Public Sub New()
Me.New("?")
End Sub
Public Sub New(ByVal defaultString As String)
Me.DefaultString = defaultString
' Create table of mappings
mapping = New Dictionary(Of UShort, ULong)
mapping.Add(&H24C8, &H53)
mapping.Add(&H2075, &H35)
mapping.Add(&H221E, &H49004E0046)
End Sub
Public Overrides Function CreateFallbackBuffer() As System.Text.EncoderFallbackBuffer
Return New CustomMapperFallbackBuffer(Me)
End Function
Public Overrides ReadOnly Property MaxCharCount As Integer
Get
Return 3
End Get
End Property
End Class
Följande kod definierar CustomMapperFallbackBuffer
klassen, som härleds från EncoderFallbackBuffer. Ordlistan som innehåller mappningar som passar bäst och som definieras i instansen CustomMapper
är tillgänglig från dess klasskonstruktor. Metoden Fallback
returnerar true
om något av de Unicode-tecken som ASCII-kodaren inte kan koda definieras i mappningsordlistan. Annars returneras false
. För varje återställning anger den privata count
variabeln antalet tecken som återstår att returnera, och den privata index
variabeln anger positionen i strängbufferten, charsToReturn
, för nästa tecken som ska returneras.
public class CustomMapperFallbackBuffer : EncoderFallbackBuffer
{
int count = -1; // Number of characters to return
int index = -1; // Index of character to return
CustomMapper fb;
string charsToReturn;
public CustomMapperFallbackBuffer(CustomMapper fallback)
{
this.fb = fallback;
}
public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
{
// Do not try to map surrogates to ASCII.
return false;
}
public override bool Fallback(char charUnknown, int index)
{
// Return false if there are already characters to map.
if (count >= 1) return false;
// Determine number of characters to return.
charsToReturn = String.Empty;
ushort key = Convert.ToUInt16(charUnknown);
if (fb.mapping.ContainsKey(key)) {
byte[] bytes = BitConverter.GetBytes(fb.mapping[key]);
int ctr = 0;
foreach (var byt in bytes) {
if (byt > 0) {
ctr++;
charsToReturn += (char) byt;
}
}
count = ctr;
}
else {
// Return default.
charsToReturn = fb.DefaultString;
count = 1;
}
this.index = charsToReturn.Length - 1;
return true;
}
public override char GetNextChar()
{
// We'll return a character if possible, so subtract from the count of chars to return.
count--;
// If count is less than zero, we've returned all characters.
if (count < 0)
return '\u0000';
this.index--;
return charsToReturn[this.index + 1];
}
public override bool MovePrevious()
{
// Original: if count >= -1 and pos >= 0
if (count >= -1) {
count++;
return true;
}
else {
return false;
}
}
public override int Remaining
{
get { return count < 0 ? 0 : count; }
}
public override void Reset()
{
count = -1;
index = -1;
}
}
Public Class CustomMapperFallbackBuffer : Inherits EncoderFallbackBuffer
Dim count As Integer = -1 ' Number of characters to return
Dim index As Integer = -1 ' Index of character to return
Dim fb As CustomMapper
Dim charsToReturn As String
Public Sub New(ByVal fallback As CustomMapper)
MyBase.New()
Me.fb = fallback
End Sub
Public Overloads Overrides Function Fallback(ByVal charUnknownHigh As Char, ByVal charUnknownLow As Char, ByVal index As Integer) As Boolean
' Do not try to map surrogates to ASCII.
Return False
End Function
Public Overloads Overrides Function Fallback(ByVal charUnknown As Char, ByVal index As Integer) As Boolean
' Return false if there are already characters to map.
If count >= 1 Then Return False
' Determine number of characters to return.
charsToReturn = String.Empty
Dim key As UShort = Convert.ToUInt16(charUnknown)
If fb.mapping.ContainsKey(key) Then
Dim bytes() As Byte = BitConverter.GetBytes(fb.mapping.Item(key))
Dim ctr As Integer
For Each byt In bytes
If byt > 0 Then
ctr += 1
charsToReturn += Chr(byt)
End If
Next
count = ctr
Else
' Return default.
charsToReturn = fb.DefaultString
count = 1
End If
Me.index = charsToReturn.Length - 1
Return True
End Function
Public Overrides Function GetNextChar() As Char
' We'll return a character if possible, so subtract from the count of chars to return.
count -= 1
' If count is less than zero, we've returned all characters.
If count < 0 Then Return ChrW(0)
Me.index -= 1
Return charsToReturn(Me.index + 1)
End Function
Public Overrides Function MovePrevious() As Boolean
' Original: if count >= -1 and pos >= 0
If count >= -1 Then
count += 1
Return True
Else
Return False
End If
End Function
Public Overrides ReadOnly Property Remaining As Integer
Get
Return If(count < 0, 0, count)
End Get
End Property
Public Overrides Sub Reset()
count = -1
index = -1
End Sub
End Class
Följande kod instansierar CustomMapper
sedan objektet och skickar en instans av det till Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) metoden. Utdata anger att den bästa återställningsimplementeringen hanterar de tre icke-ASCII-tecknen i den ursprungliga strängen.
using System;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main()
{
Encoding enc = Encoding.GetEncoding("us-ascii", new CustomMapper(), new DecoderExceptionFallback());
string str1 = "\u24C8 \u2075 \u221E";
Console.WriteLine(str1);
for (int ctr = 0; ctr <= str1.Length - 1; ctr++) {
Console.Write("{0} ", Convert.ToUInt16(str1[ctr]).ToString("X4"));
if (ctr == str1.Length - 1)
Console.WriteLine();
}
Console.WriteLine();
// Encode the original string using the ASCII encoder.
byte[] bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");
// Decode the ASCII bytes.
string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
Imports System.Text
Imports System.Collections.Generic
Module Module1
Sub Main()
Dim enc As Encoding = Encoding.GetEncoding("us-ascii", New CustomMapper(), New DecoderExceptionFallback())
Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&H24C8), ChrW(&H2075), ChrW(&H221E))
Console.WriteLine(str1)
For ctr As Integer = 0 To str1.Length - 1
Console.Write("{0} ", Convert.ToUInt16(str1(ctr)).ToString("X4"))
If ctr = str1.Length - 1 Then Console.WriteLine()
Next
Console.WriteLine()
' Encode the original string using the ASCII encoder.
Dim bytes() As Byte = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()
' Decode the ASCII bytes.
Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module