Cara menggunakan kelas pengodean karakter di .NET

Artikel ini menjelaskan cara menggunakan kelas yang disediakan .NET untuk pengodean dan pendekodean teks dengan menggunakan berbagai skema pengodean. Instruksi mengasumsikan Anda telah membaca Pengantar pengodean karakter di .NET.

Enkoder dan dekoder

.NET menyediakan kelas pengodean yang mengodekan dan mendekodekan teks dengan menggunakan berbagai sistem pengodean. Misalnya, kelas UTF8Encoding menjelaskan aturan untuk pengodean ke, dan pendekodean dari, UTF-8. .NET menggunakan pengodean UTF-16 (diwakili oleh kelas UnicodeEncoding) untuk instansstring. Enkoder dan dekoder tersedia untuk skema pengodean lainnya.

Pengodean dan pendekodean juga dapat mencakup validasi. Misalnya, kelas UnicodeEncoding memeriksa semua instans char dalam rentang pengganti untuk memastikan instans berada dalam pasangan pengganti yang valid. Strategi fallback menentukan bagaimana enkoder menangani karakter yang tidak valid atau bagaimana dekoder menangani byte yang tidak valid.

Peringatan

Kelas pengodean .NET menyediakan cara untuk menyimpan dan mengonversi data karakter. Mereka tidak boleh digunakan untuk menyimpan data biner dalam bentuk string. Tergantung pada pengodean yang digunakan, mengonversi data biner ke format string dengan kelas pengodean dapat memperkenalkan perilaku yang tidak terduga dan menghasilkan data yang tidak akurat atau rusak. Untuk mengonversi data biner ke bentuk string, gunakan metode Convert.ToBase64String.

Semua kelas pengodean karakter di .NET diwarisi dari kelas System.Text.Encoding, yang merupakan kelas abstrak yang menentukan fungsionalitas yang umum untuk semua pengodean karakter. Untuk mengakses objek pengodean individual yang diimplementasikan dalam .NET, lakukan hal berikut:

  • Gunakan properti statik kelas Encoding, yang mengembalikan objek yang mewakili pengodean karakter standar yang tersedia di .NET (ASCII, UTF-7, UTF-8, UTF-16, dan UTF-32). Misalnya, properti Encoding.Unicode mengembalikan objek UnicodeEncoding. Setiap objek menggunakan fallback pengganti untuk menangani string yang tidak dapat dikodekan dan byte yang tidak dapat didekode. Untuk informasi selengkapnya, lihat Fallback pengganti.

  • Panggil konstruktor kelas pengodean. Objek untuk pengodean ASCII, UTF-7, UTF-8, UTF-16, dan UTF-32 dapat dibuat instansnya dengan cara ini. Secara default, setiap objek menggunakan fallback pengganti untuk menangani string yang tidak dapat dikodekan dan byte yang tidak dapat didecode, tetapi Anda dapat menentukan bahwa pengecualian harus dilemparkan sebagai gantinya. Untuk informasi selengkapnya, lihat Fallback pengganti dan Fallback pengecualian.

  • Panggil konstruktor Encoding(Int32) dan berikan bilangan bulat yang mewakili pengodean. Objek pengodean standar menggunakan fallback pengganti, dan halaman kode dan set karakter byte ganda (DBCS) yang mengodekan objek menggunakan fallback yang paling pas untuk menangani string yang tidak dapat mereka kodekan dan byte yang tidak dapat mereka dekode. Untuk informasi selengkapnya, lihat Fallback paling cocok.

  • Panggil metode Encoding.GetEncoding, yang mengembalikan pengodean standar, halaman kode, atau DBCS apa pun yang tersedia di .NET. Kelebihan beban memungkinkan Anda menentukan objek fallback untuk enkoder dan dekoder.

Anda dapat mengambil informasi tentang semua pengodean yang tersedia di .NET dengan memanggil metode Encoding.GetEncodings. .NET mendukung skema pengodean karakter yang tercantum dalam tabel berikut.

Kelas pengodean Deskripsi
ASCII Mengodekan rentang karakter terbatas dengan menggunakan tujuh bit byte yang lebih rendah. Karena pengodean ini hanya mendukung nilai karakter dari U+0000 melalui U+007F, dalam sebgaian besara kasus tidak memadai untuk aplikasi internasional.
UTF-7 Mewakili karakter sebagai urutan karakter ASCII 7-bit. Karakter Unicode non-ASCII diwakili oleh urutan escape karakter ASCII. UTF-7 mendukung protokol seperti email dan grup berita. Namun, UTF-7 tidak terlalu aman atau kuat. Dalam beberapa kasus, mengubah satu bit dapat secara radikal mengubah interpretasi seluruh string UTF-7. Dalam kasus lain, string UTF-7 yang berbeda dapat mengodekan teks yang sama. Untuk urutan yang mencakup karakter non-ASCII, UTF-7 membutuhkan lebih banyak ruang daripada UTF-8, dan pengodean/pendekodeannya lebih lambat. Akibatnya, Anda harus menggunakan UTF-8 bukan UTF-7 jika memungkinkan.
UTF-8 Mewakili setiap titik kode Unicode sebagai urutan satu hingga empat byte. UTF-8 mendukung ukuran data 8-bit dan bekerja dengan baik dengan banyak sistem operasi yang ada. Untuk rentang karakter ASCII, UTF-8 identik dengan pengodean ASCII dan memungkinkan satu set karakter yang lebih luas. Namun, untuk skrip Cina-Jepang-Korea (CJK), UTF-8 dapat memerlukan tiga byte untuk setiap karakter, dan dapat menyebabkan ukuran data yang lebih besar daripada UTF-16. Terkadang jumlah data ASCII, seperti tag HTML, membenarkan peningkatan ukuran untuk rentang CJK.
UTF-16 Mewakili setiap titik kode Unicode sebagai urutan satu atau dua bilangan bulat 16-bit. Karakter Unicode yang paling umum hanya memerlukan satu titik kode UTF-16, meskipun karakter tambahan Unicode (U+10000 dan yang lebih besar) memerlukan dua titik kode pengganti UTF-16. Baik perintah byte little-endian maupun big-endian didukung. Pengodean UTF-16 digunakan oleh runtime bahasa umum untuk mewakili nilai Char dan String, dan digunakan oleh sistem operasi Windows untuk mewakili nilai WCHAR.
UTF-32 Mewakili setiap titik kode Unicode sebagai bilangan bulat 32-bit. Baik perintah byte little-endian maupun big-endian didukung. Pengodean UTF-32 digunakan ketika aplikasi ingin menghindari perilaku titik kode pengganti pengodean UTF-16 pada sistem operasi di mana ruang yang dikodekan terlalu penting. Glif tunggal yang dirender pada layar masih dapat dikodekan dengan lebih dari satu karakter UTF-32.
Pengodean ANSI/ISO Menyediakan dukungan untuk berbagai halaman kode. Pada sistem operasi Windows, halaman kode digunakan untuk mendukung bahasa atau kelompok bahasa tertentu. Untuk tabel yang mencantumkan halaman kode yang didukung oleh .NET, lihat kelas Encoding. Anda dapat mengambil objek pengodean untuk halaman kode tertentu dengan memanggil metode Encoding.GetEncoding(Int32). Halaman kode berisi 256 titik kode dan berbasis nol. Di sebagian besar halaman kode, poin kode 0 hingga 127 mewakili set karakter ASCII, dan poin kode 128 hingga 255 berbeda secara signifikan antara halaman kode. Misalnya, halaman kode 1252 menyediakan karakter untuk sistem penulisan Latin, termasuk bahasa Inggris, Jerman, dan Prancis. 128 titik kode terakhir di halaman kode 1252 berisi karakter aksen. Halaman kode 1253 menyediakan kode karakter yang diperlukan dalam sistem penulisan Yunani. 128 poin kode terakhir di halaman kode 1253 berisi karakter Yunani. Akibatnya, aplikasi yang bergantung pada halaman kode ANSI tidak dapat menyimpan bahasa Yunani dan Jerman dalam aliran teks yang sama kecuali menyertakan pengidentifikasi yang menunjukkan halaman kode yang direferensikan.
Pengodean set karakter byte ganda (DBCS) Mendukung bahasa, seperti Mandarin, Jepang, dan Korea, yang berisi lebih dari 256 karakter. Dalam DBCS, sepasang titik kode (byte ganda) mewakili setiap karakter. Properti Encoding.IsSingleByte mengembalikan false untuk pengodean DBCS. Anda dapat mengambil objek pengodean untuk DBCS tertentu dengan memanggil metode Encoding.GetEncoding(Int32). Ketika sebuah aplikasi menangani data DBCS, byte pertama dari karakter DBCS (byte utama) diproses dalam kombinasi dengan byte jejak yang segera mengikutinya. Karena sepasang titik kode byte ganda dapat mewakili karakter yang berbeda tergantung pada halaman kode, skema ini masih tidak memungkinkan untuk kombinasi dua bahasa, seperti Jepang dan Cina, dalam aliran data yang sama.

Pengodean ini memungkinkan Anda untuk bekerja dengan karakter Unicode serta dengan pengodean yang paling umum digunakan dalam aplikasi lama. Selain itu, Anda dapat membuat pengodean kustom dengan menentukan kelas yang berasal dari Encoding dan menimpa anggotanya.

Dukungan pengodean .NET Core

Secara default, .NET Core tidak menyediakan pengodean halaman kode apa pun selain halaman kode 28591 dan pengodean Unicode, seperti UTF-8 dan UTF-16. Namun, Anda dapat menambahkan pengodean halaman kode yang ditemukan di aplikasi Windows standar yang menargetkan .NET ke aplikasi Anda. Untuk informasi selengkapnya, lihat topik CodePagesEncodingProvider.

Memilih Kelas Pengodean

Jika Anda memiliki kesempatan untuk memilih pengodean yang akan digunakan oleh aplikasi Anda, Anda harus menggunakan pengodean Unicode, sebaiknya UTF8Encoding atau UnicodeEncoding. (.NET juga mendukung pengodean Unicode ketiga, UTF32Encoding.)

Jika Anda berencana menggunakan pengodean ASCII (ASCIIEncoding), pilih UTF8Encoding sebagai gantinya. Kedua pengodean identik untuk kumpulan karakter ASCII, tetapi UTF8Encoding memiliki keuntungan berikut:

  • Dapat mewakili setiap karakter Unicode, sedangkan ASCIIEncoding hanya mendukung nilai karakter Unicode antara U+0000 dan U+007F.

  • Memberikan deteksi kesalahan dan keamanan yang lebih baik.

  • Telah disetel untuk menjadi secepat mungkin dan seharusnya lebih cepat daripada pengodean lainnya. Bahkan untuk konten yang sepenuhnya ASCII, operasi yang dilakukan dengan UTF8Encoding lebih cepat daripada operasi yang dilakukan dengan ASCIIEncoding.

Anda harus mempertimbangkan untuk menggunakan ASCIIEncoding hanya untuk aplikasi warisan. Namun, bahkan untuk aplikasi warisan, UTF8Encoding mungkin menjadi pilihan yang lebih baik karena alasan berikut (dengan asumsi pengaturan default):

  • Jika aplikasi Anda memiliki konten yang tidak hanya ASCII dan mengodekannya dengan ASCIIEncoding, setiap karakter non-ASCII dikodekan sebagai tanda tanya (?). Jika aplikasi kemudian mendekodekan data ini, informasinya hilang.

  • Jika aplikasi Anda memiliki konten yang tidak hanya ASCII dan mengodekannya dengan UTF8Encoding, hasilnya tampak tidak dapat dimengerti jika ditafsirkan sebagai ASCII. Namun, jika aplikasi kemudian menggunakan dekoder UTF-8 untuk mendekodekan data ini, data melakukan perjalanan pulang pergi dengan sukses.

Dalam aplikasi web, karakter yang dikirim ke klien sebagai tanggapan atas permintaan web harus mencerminkan pengodean yang digunakan pada klien. Dalam kebanyakan kasus, Anda harus mengatur properti HttpResponse.ContentEncoding ke nilai yang dikembalikan oleh properti HttpRequest.ContentEncoding untuk menampilkan teks dalam pengodean yang diharapkan pengguna.

Menggunakan Objek Pengodean

Enkoder mengubah string karakter (paling umum, karakter Unicode) menjadi ekuivalen numeriknya (byte). Misalnya, Anda dapat menggunakan enkoder ASCII untuk mengonversi karakter Unicode ke ASCII sehingga dapat ditampilkan di konsol. Untuk melakukan konversi, Anda memanggil metode Encoding.GetBytes. Jika Anda ingin menentukan berapa banyak byte yang diperlukan untuk menyimpan karakter yang dikodekan sebelum melakukan pengodean, Anda dapat memanggil metode GetByteCount.

Contoh berikut menggunakan larik byte tunggal untuk mengodekan string dalam dua operasi terpisah. Ini mempertahankan indeks yang menunjukkan posisi awal dalam larik byte untuk set byte yang dikodekan ASCII berikutnya. Ini memanggil metode ASCIIEncoding.GetByteCount(String) untuk memastikan bahwa larik byte cukup besar untuk mengakomodasi string yang dikodekan. Kemudian memanggil metode ASCIIEncoding.GetBytes(String, Int32, Int32, Byte[], Int32) untuk mengodekan karakter dalam string.

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.

Dekoder mengubah larik byte yang mencerminkan pengodean karakter tertentu menjadi satu set karakter, baik dalam larik karakter atau dalam string. Untuk mendekode larik byte ke dalam larik karakter, Anda memanggil metode Encoding.GetChars. Untuk mendekode larik byte ke dalam string, Anda memanggil metode GetString. Jika Anda ingin menentukan berapa banyak byte yang diperlukan untuk menyimpan karakter yang dikodekan sebelum melakukan pengodean, Anda dapat memanggil metode GetCharCount.

Contoh berikut mengodekan tiga string, kemudian mendekodekan mereka menjadi satu larik karakter. Ini mempertahankan indeks yang mengindikasikan posisi awal dalam larik karakter untuk set karakter yang didekodekan berikutnya. Ini memanggil metode GetCharCount untuk memastikan bahwa larik karakter cukup besar untuk mengakomodasi semua karakter yang didekodekan. Kemudian memanggil metode ASCIIEncoding.GetChars(Byte[], Int32, Int32, Char[], Int32) untuk mendekode larik byte.

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.

Metode pengodean dan pendekodean kelas yang berasal dari Encoding dirancang untuk bekerja pada sekumpulan data lengkap; yaitu, semua data yang akan dikodekan atau didekodekan disediakan dalam satu panggilan metode. Namun, dalam beberapa kasus, data tersedia dalam aliran, dan data yang akan dikodekan atau diterjemahkan mungkin hanya tersedia dari operasi baca terpisah. Ini memerlukan operasi pengodean atau pendekodean untuk mengingat status yang disimpan dari pemanggilan sebelumnya. Metode kelas yang berasal dari Encoder dan Decoder mampu menangani operasi pengodean dan pendekodean yang mencakup beberapa panggilan metode.

Objek Encoder untuk pengodean tertentu tersedia dari properti Encoding.GetEncoder pengodean tersebut. Objek Decoder untuk pengodean tertentu tersedia dari properti Encoding.GetDecoder pengodean tersebut. Untuk operasi pendekodean, perhatikan bahwa kelas yang berasal dari Decoder menyertakan metode Decoder.GetChars, tetapi tidak memiliki metode yang sesuai dengan Encoding.GetString.

Contoh berikut mengilustrasikan perbedaan antara menggunakan metode Encoding.GetString dan Decoder.GetChars untuk mendekode larik byte Unicode. Contoh tersebut mengodekan string yang berisi beberapa karakter Unicode ke file, kemudian menggunakan dua metode pedekodean untuk mendekodekan mereka sepuluh byte sekaligus. Karena pasangan pengganti terjadi dalam byte kesepuluh dan kesebelas, itu didekodekan dalam panggilan metode terpisah. Seperti yang ditunjukkan oleh output, metode Encoding.GetString tidak dapat mendekode byte dengan benar dan menggantinya dengan U+FFFD (KARAKTER PENGGANTI). Di sisi lain, metode Decoder.GetChars dapat berhasil mendekode larik byte untuk mendapatkan string asli.

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

Memilih Strategi Fallback

Ketika sebuah metode mencoba untuk mengodekan atau mendekode karakter tetapi tidak ada pemetaan, ia harus mengimplementasikan strategi fallback yang menentukan bagaimana pemetaan yang gagal harus ditangani. Ada tiga jenis strategi fallback:

  • Fallback paling pas

  • Fallback penggantian

  • Fallback pengecualian

Penting

Masalah yang paling umum dalam operasi pengodean terjadi ketika karakter Unicode tidak dapat dipetakan ke pengodean halaman kode tertentu. Masalah paling umum dalam operasi pendeodean terjadi ketika urutan byte yang tidak valid tidak dapat diterjemahkan ke dalam karakter Unicode yang valid. Untuk alasan ini, Anda harus tahu strategi fallback mana yang digunakan objek pengodean tertentu. Bila memungkinkan, Anda harus menentukan strategi fallback yang digunakan oleh objek pengodean saat Anda membuat instans objek.

Fallback Paling Pas

Ketika karakter tidak memiliki kecocokan yang tepat dalam pengodean target, enkoder dapat mencoba memetakannya ke karakter yang sama. (Fallback paling pas sebagian besar adalah masalah pengodean, bukan masalah pendekodean. Ada sangat sedikit halaman kode yang berisi karakter yang tidak berhasil dipetakan ke Unicode.) Fallback paling pas adalah default untuk halaman kode dan pengodean set karakter byte ganda yang diambil oleh kelebihan beban Encoding.GetEncoding(Int32) dan Encoding.GetEncoding(String).

Catatan

Secara teori, kelas pengodean Unicode yang disediakan dalam .NET (UTF8Encoding, UnicodeEncoding, dan UTF32Encoding) mendukung setiap karakter di setiap set karakter, sehingga dapat digunakan untuk menghilangkan masalah fallback paling pas.

Strategi yang paling cocok bervariasi untuk halaman kode yang berbeda. Misalnya, untuk beberapa halaman kode, karakter Latin lebar penuh memetakan ke karakter Latin setengah lebar yang lebih umum. Untuk halaman kode lainnya, pemetaan ini tidak dibuat. Bahkan di bawah strategi paling cocok yang agresif, tidak ada yang kecocokan bisa dibayangkan untuk beberapa karakter dalam beberapa pengodean. Misalnya, ideograf Cina tidak memiliki pemetaan yang masuk akal ke halaman kode 1252. Dalam hal ini, string pengganti digunakan. Secara default, string ini hanyalah satu TANDA TANYA (U +003F).

Catatan

Strategi yang paling cocok tidak didokumentasikan secara rinci. Namun, beberapa halaman kode didokumentasikan di situs web Unicode Consortium. Harap tinjau file readme.txt di folder tersebut untuk deskripsi tentang cara menginterpretasikan file pemetaan.

Contoh berikut menggunakan halaman kode 1252 (halaman kode Windows untuk bahasa Eropa Barat) untuk menggambarkan pemetaan yang paling cocok dan kekurangannya. Metode Encoding.GetEncoding(Int32) digunakan untuk mengambil objek pengodean untuk halaman kode 1252. Secara default, ia menggunakan pemetaan yang paling cocok untuk karakter Unicode yang tidak didukungnya. Contoh ini membuat instans string yang berisi tiga karakter non-ASCII - HURUF KAPITAL LATIN S DILINGKARI (U + 24C8), SUPERSCRIPT FIVE (U + 2075), dan INFINITY (U + 221E) - dipisahkan oleh spasi. Seperti yang ditunjukkan oleh output dari contoh, ketika string dikodekan, tiga karakter non-spasi asli digantikan oleh TANDA TANYA (U +003F), DIGIT LIMA (U +0035), dan DIGIT DELAPAN (U +0038). DIGIT DELAPAN adalah pengganti yang sangat buruk untuk karakter INFINITY yang tidak didukung, dan TANDA TANYA menunjukkan bahwa tidak ada pemetaan yang tersedia untuk karakter aslinya.

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

Pemetaan yang paling cocok adalah perilaku default untuk objek Encoding yang mengodekan data Unicode ke dalam data halaman kode, dan ada aplikasi warisan yang mengandalkan perilaku ini. Namun, sebagian besar aplikasi baru harus menghindari perilaku yang paling cocok untuk alasan keamanan. Misalnya, aplikasi tidak boleh menempatkan nama domain melalui pengodean yang paling cocok.

Catatan

Anda juga dapat menerapkan pemetaan fallback paling pas untuk pengodean. Untuk informasi selengkapnya, lihat bagian Mengimplementasikan Strategi Fallback Kustom.

Jika fallback paling pas adalah default untuk objek pengodean, Anda dapat memilih strategi fallback lain saat Anda mengambil objek Encoding dengan memanggil kelebihan beban Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) atau Encoding.GetEncoding(String, EncoderFallback, DecoderFallback). Bagian berikut mencakup contoh yang menggantikan setiap karakter yang tidak dapat dipetakan ke halaman kode 1252 dengan tanda bintang (*).

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

Fallback Penggantian

Ketika karakter tidak memiliki kecocokan yang tepat dalam skema target, tetapi tidak ada karakter yang sesuai yang dapat dipetakan, aplikasi dapat menentukan karakter atau string pengganti. Ini adalah perilaku default untuk dekoder Unicode, yang menggantikan urutan dua byte yang tidak dapat didekode dengan REPLACEMENT_CHARACTER (U + FFFD). Ini juga merupakan perilaku default kelas ASCIIEncoding, yang menggantikan setiap karakter yang tidak dapat dikodekan atau didekodekan dengan tanda tanya. Contoh berikut mengilustrasikan penggantian karakter untuk string Unicode dari contoh sebelumnya. Seperti yang ditunjukkan oleh output, setiap karakter yang tidak dapat didekodekan ke dalam nilai byte ASCII digantikan oleh 0x3F, yang merupakan kode ASCII untuk tanda tanya.

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 menyertakan kelas EncoderReplacementFallback dan DecoderReplacementFallback, yang menggantikan string pengganti jika karakter tidak memetakan dengan tepat dalam operasi pengodean atau pendekodean. Secara default, string pengganti ini adalah tanda tanya, tetapi Anda dapat memanggil kelebihan beban konstruktor kelas untuk memilih string yang berbeda. Biasanya, string pengganti adalah karakter tunggal, meskipun ini bukan persyaratan. Contoh berikut mengubah perilaku enkoder halaman kode 1252 dengan membuat instans objek EncoderReplacementFallback yang menggunakan tanda bintang (*) sebagai string pengganti.

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

Catatan

Anda juga dapat menerapkan kelas pengganti untuk pengodean. Untuk informasi selengkapnya, lihat bagian Mengimplementasikan Strategi Fallback Kustom.

Selain TANDA TANYA (U +003F), KARAKTER PENGGANTI (U + FFFD) Unicode umumnya digunakan sebagai string pengganti, terutama ketika mendekode urutan byte yang tidak berhasil diterjemahkan ke dalam karakter Unicode. Namun, Anda bebas memilih string pengganti apa pun, dan dapat berisi beberapa karakter.

Fallback Pengecualian

Alih-alih memberikan fallback paling pas atau string pengganti, enkoder dapat melempar EncoderFallbackException jika tidak dapat mengodekan sekumpulan karakter, dan dekoder dapat melempar DecoderFallbackException jika tidak dapat mendekode larik byte. Untuk melempar pengecualian dalam operasi pengodean dan pendekodean, Anda menyediakan objek EncoderExceptionFallback dan objek DecoderExceptionFallback, masing-masing, ke metode Encoding.GetEncoding(String, EncoderFallback, DecoderFallback). Contoh berikut mengilustrasikan fallback pengecualian dengan kelas ASCIIEncoding.

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.

Catatan

Anda juga dapat menerapkan penangan pengecualian kustom untuk operasi pengodean. Untuk informasi selengkapnya, lihat bagian Mengimplementasikan Strategi Fallback Kustom.

Objek EncoderFallbackException dan DecoderFallbackException memberikan informasi berikut tentang kondisi yang menyebabkan pengecualian:

Meskipun objek EncoderFallbackException dan DecoderFallbackException memberikan informasi diagnostik yang memadai tentang pengecualian, objek tersebut tidak menyediakan akses ke buffer pengodean atau pendekodean. Oleh karena itu, mereka tidak mengizinkan data yang tidak valid diganti atau diperbaiki dalam metode pengodean atau pendekodean.

Mengimplementasikan Strategi Fallback Kustom

Selain pemetaan yang paling cocok yang diimplementasikan secara internal oleh halaman kode, .NET mencakup kelas-kelas berikut untuk mengimplementasikan strategi fallback:

Selain itu, Anda dapat menerapkan solusi kustom yang menggunakan fallback paling pas, fallback pengganti, atau fallback pengecualian, dengan mengikuti langkah-langkah berikut:

  1. Mendapatkan kelas dari EncoderFallback untuk operasi pengodean, dan dari DecoderFallback untuk operasi pendekodean.

  2. Mendapatkan kelas dari EncoderFallbackBuffer untuk operasi pengodean, dan dari DecoderFallbackBuffer untuk operasi pendekodean.

  3. Untuk fallback pengecualian, jika kelas EncoderFallbackException dan DecoderFallbackException yang telah ditentukan sebelumnya tidak memenuhi kebutuhan Anda, dapatkan kelas dari objek pengecualian seperti Exception atau ArgumentException.

Berasal dari EncoderFallback atau DecoderFallback

Untuk mengimplementasikan solusi fallback kustom, Anda harus membuat kelas yang mewarisi dari EncoderFallback operasi pengodean, dan dari DecoderFallback untuk operasi pendekodean. Instans kelas-kelas ini diteruskan ke metode Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) dan berfungsi sebagai perantara antara kelas pengodean dan implementasi fallback.

Saat Anda membuat solusi fallback kustom untuk enkoder atau dekoder, Anda harus mengimplementasikan anggota berikut:

Berasal dari EncoderFallbackBuffer atau DecoderFallbackBuffer

Untuk mengimplementasikan solusi fallback kustom, Anda juga harus membuat kelas yang mewarisi dari EncoderFallbackBuffer operasi pengodean, dan dari DecoderFallbackBuffer untuk operasi pendekodean. Instans kelas-kelas ini dikembalikan oleh metode CreateFallbackBuffer dari kelas EncoderFallback dan DecoderFallback. Metode EncoderFallback.CreateFallbackBuffer ini dipanggil oleh enkoder ketika menemukan karakter pertama yang tidak dapat dikodekan, dan metode DecoderFallback.CreateFallbackBuffer dipanggil oleh dekoder ketika menemukan satu atau beberapa byte yang tidak dapat didekodekan. Kelas EncoderFallbackBuffer dan DecoderFallbackBuffer menyediakan implementasi fallback. Setiap instans mewakili buffer yang berisi karakter fallback yang akan menggantikan karakter yang tidak dapat dikodekan atau urutan byte yang tidak dapat didekodekan.

Saat Anda membuat solusi fallback kustom untuk enkoder atau dekoder, Anda harus mengimplementasikan anggota berikut:

Jika implementasi fallback adalah fallback paling pas atau fallback pengganti, kelas yang berasal dari EncoderFallbackBuffer dan DecoderFallbackBuffer juga mempertahankan dua bidang instans privat: jumlah karakter yang tepat dalam buffer; dan indeks karakter berikutnya dalam buffer untuk dikembalikan.

Contoh EncoderFallback

Contoh sebelumnya menggunakan fallback pengganti untuk menggantikan karakter Unicode yang tidak sesuai dengan karakter ASCII dengan tanda bintang (*). Contoh berikut menggunakan implementasi fallback paling pas untuk memberikan pemetaan karakter non-ASCII yang lebih baik.

Kode berikut mendefinisikan kelas bernama CustomMapper yang berasal dari EncoderFallback untuk menangani pemetaan karakter non-ASCII yang paling sesuai. Metode CreateFallbackBuffer mengembalikan objek CustomMapperFallbackBuffer, yang menyediakan implementasi EncoderFallbackBuffer. Kelas CustomMapper menggunakan objek Dictionary<TKey,TValue> untuk menyimpan pemetaan karakter Unicode yang tidak didukung (nilai kunci) dan karakter 8-bit yang sesuai (yang disimpan dalam dua byte berturut-turut dalam bilangan bulat 64-bit). Untuk membuat pemetaan ini tersedia untuk buffer fallback, instans CustomMapper diteruskan sebagai parameter ke konstruktor kelas CustomMapperFallbackBuffer. Karena pemetaan terpanjang adalah string "INF" untuk karakter Unicode U+221E, properti MaxCharCount mengembalikan 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

Kode berikut mendefinisikan kelas CustomMapperFallbackBuffer, yang berasal dari EncoderFallbackBuffer. Kamus yang berisi pemetaan yang paling sesuai dan yang didefinisikan dalam instans CustomMapper tersedia dari konstruktor kelasnya. Metode Fallback mengembalikan true jika salah satu karakter Unicode yang tidak dapat dikodekan oleh enkoder ASCII didefinisikan dalam kamus pemetaan; jika tidak, ia mengembalikan false. Untuk setiap fallback, variabel privat count menunjukkan jumlah sisa karakter yang akan dikembalikan, dan variabel privat index mengindikasikan posisi dalam buffer string, charsToReturn, dari karakter berikutnya yang akan dikembalikan.

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

Kode berikut kemudian membuat instans objek CustomMapper dan meneruskan instansnya ke metode Encoding.GetEncoding(String, EncoderFallback, DecoderFallback). Output mengindikasikan bahwa implementasi fallback paling pas berhasil menangani tiga karakter non-ASCII dalam string asli.

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

Lihat juga