다음을 통해 공유


.NET에서 문자 인코딩 클래스를 사용하는 방법

이 문서에서는 다양한 인코딩 체계를 사용하여 .NET에서 제공하는 클래스를 사용하여 텍스트를 인코딩하고 디코딩하는 방법을 설명합니다. 지침에서는 .NET의 문자 인코딩 소개를 읽은 것으로 가정합니다.

인코더 및 디코더

.NET은 다양한 인코딩 시스템을 사용하여 텍스트를 인코딩하고 디코딩하는 인코딩 클래스를 제공합니다. 예를 들어 UTF8Encoding 클래스는 UTF-8에서 인코딩 및 디코딩하는 규칙을 설명합니다. .NET은 string 인스턴스에 UTF-16 인코딩(UnicodeEncoding 클래스로 표시됨)을 사용합니다. 인코더 및 디코더는 다른 인코딩 스키마에 사용할 수 있습니다.

인코딩 및 디코딩에는 유효성 검사도 포함될 수 있습니다. 예를 들어 UnicodeEncoding 클래스는 서로게이트 범위의 모든 char 인스턴스를 검사하여 유효한 서로게이트 쌍에 있는지 확인합니다. 대체 전략은 인코더가 잘못된 문자를 처리하는 방법 또는 디코더가 잘못된 바이트를 처리하는 방법을 결정합니다.

경고

.NET 인코딩 클래스는 문자 데이터를 저장하고 변환하는 방법을 제공합니다. 문자열 형식으로 이진 데이터를 저장하는 데 사용하면 안 됩니다. 사용되는 인코딩에 따라 인코딩 클래스를 사용하여 이진 데이터를 문자열 형식으로 변환하면 예기치 않은 동작이 발생하며 부정확하거나 손상된 데이터가 생성될 수 있습니다. 이진 데이터를 문자열 형식으로 변환하려면 Convert.ToBase64String 메서드를 사용합니다.

.NET의 모든 문자 인코딩 클래스는 모든 문자 인코딩에 공통된 기능을 정의하는 추상 클래스인 System.Text.Encoding 클래스에서 상속됩니다. .NET에서 구현된 개별 인코딩 개체에 액세스하려면 다음을 수행합니다.

  • .NET(ASCII, UTF-7, UTF-8, UTF-16 및 UTF-32)에서 사용할 수 있는 표준 문자 인코딩을 나타내는 개체를 반환하는 Encoding 클래스의 정적 속성을 사용합니다. 예를 들어 Encoding.Unicode 속성은 UnicodeEncoding 개체를 반환합니다. 각 개체는 대체 대체를 사용하여 인코딩할 수 없는 문자열과 디코딩할 수 없는 바이트를 처리합니다. 자세한 내용은 대체 옵션을 참조하세요.

  • 인코딩의 클래스 생성자를 호출합니다. 이러한 방식으로 ASCII, UTF-7, UTF-8, UTF-16 및 UTF-32 인코딩에 대한 개체를 인스턴스화할 수 있습니다. 기본적으로 각 개체는 대체 대체를 사용하여 인코딩할 수 없는 문자열과 디코딩할 수 없는 바이트를 처리하지만 대신 예외를 throw하도록 지정할 수 있습니다. 자세한 내용은 대체 대체예외 대체참조하세요.

  • Encoding(Int32) 생성자를 호출하고 인코딩을 나타내는 정수로 전달합니다. 표준 인코딩 개체는 대체 대체를 사용하며, 코드 페이지와 DBCS(더블바이트 문자 집합) 인코딩 개체는 인코딩할 수 없는 문자열과 디코딩할 수 없는 바이트를 처리하는 데 가장 적합한 대체를 사용합니다. 자세한 내용은 최적 대체참조하세요.

  • .NET에서 사용할 수 있는 표준, 코드 페이지 또는 DBCS 인코딩을 반환하는 Encoding.GetEncoding 메서드를 호출합니다. 오버로드를 사용하면 인코더와 디코더 모두에 대한 대체 개체를 지정할 수 있습니다.

Encoding.GetEncodings 메서드를 호출하여 .NET에서 사용할 수 있는 모든 인코딩에 대한 정보를 검색할 수 있습니다. .NET은 다음 표에 나열된 문자 인코딩 구성표를 지원합니다.

인코딩 클래스 설명
ASCII 바이트의 하위 7비트를 사용하여 제한된 문자 범위를 인코딩합니다. 이 인코딩은 문자 값 U+0000부터 U+007F까지의 범위만 지원하기 때문에 대부분의 경우 국제화된 애플리케이션에는 적합하지 않습니다.
UTF-7 문자를 7비트 ASCII 문자의 시퀀스로 나타냅니다. 비 ASCII 유니코드 문자는 ASCII 문자의 이스케이프 시퀀스로 표시됩니다. UTF-7은 이메일 및 뉴스 그룹과 같은 프로토콜을 지원합니다. 그러나 UTF-7은 특히 안전하거나 강력하지 않습니다. 경우에 따라 한 비트를 변경하면 전체 UTF-7 문자열의 해석이 근본적으로 변경됩니다. 다른 경우에는 다른 UTF-7 문자열이 동일한 텍스트를 인코딩할 수 있습니다. ASCII가 아닌 문자를 포함하는 시퀀스의 경우 UTF-7에는 UTF-8보다 더 많은 공간이 필요하며 인코딩/디코딩 속도가 느립니다. 따라서 가능하면 UTF-7 대신 UTF-8을 사용해야 합니다.
UTF-8 각 유니코드 코드 지점을 1~4바이트의 시퀀스로 나타냅니다. UTF-8은 8비트 데이터 크기를 지원하며 많은 기존 운영 체제에서 잘 작동합니다. ASCII 문자 범위의 경우 UTF-8은 ASCII 인코딩과 동일하며 더 광범위한 문자 집합을 허용합니다. 그러나 CJK(중국어Japanese-Korean) 스크립트의 경우 UTF-8에는 각 문자에 대해 3바이트가 필요할 수 있으며 UTF-16보다 더 큰 데이터 크기가 발생할 수 있습니다. 경우에 따라 HTML 태그와 같은 ASCII 데이터의 양이 CJK 범위의 증가된 크기를 정당화합니다.
UTF-16 각 유니코드 코드 지점을 하나 또는 두 개의 16비트 정수 시퀀스로 나타냅니다. 유니코드 보조 문자(U+10000 이상)에는 두 개의 UTF-16 서로게이트 코드 포인트가 필요하지만 가장 일반적인 유니코드 문자에는 UTF-16 코드 포인트가 하나만 필요합니다. little-endian 및 big-endian 바이트 순서가 모두 지원됩니다. UTF-16 인코딩은 공용 언어 런타임에서 CharString 값을 나타내는 데 사용되며 Windows 운영 체제에서 WCHAR 값을 나타내는 데 사용됩니다.
UTF-32 각 유니코드 코드 지점을 32비트 정수로 나타냅니다. little-endian 및 big-endian 바이트 순서가 모두 지원됩니다. UTF-32 인코딩은 인코딩된 공간이 너무 중요한 운영 체제에서 UTF-16 인코딩의 서로게이트 코드 포인트 동작을 방지하려는 경우에 사용됩니다. 디스플레이에 렌더링된 단일 문자 모양은 여전히 둘 이상의 UTF-32 문자로 인코딩할 수 있습니다.
ANSI/ISO 인코딩 다양한 코드 페이지를 지원합니다. Windows 운영 체제에서 코드 페이지는 특정 언어 또는 언어 그룹을 지원하는 데 사용됩니다. .NET에서 지원하는 코드 페이지를 나열하는 테이블은 Encoding 클래스를 참조하세요. Encoding.GetEncoding(Int32) 메서드를 호출하여 특정 코드 페이지에 대한 인코딩 개체를 검색할 수 있습니다. 코드 페이지에는 256개의 코드 포인트가 포함되어 있으며 0부터 시작하는 것입니다. 대부분의 코드 페이지에서 코드 포인트 0~127은 ASCII 문자 집합을 나타내고 코드 포인트 128~255는 코드 페이지 간에 크게 다릅니다. 예를 들어 코드 페이지 1252는 영어, 독일어 및 프랑스어를 비롯한 라틴어 쓰기 시스템에 대한 문자를 제공합니다. 코드 페이지 1252의 마지막 128개 코드 포인트에는 악센트 문자가 포함되어 있습니다. 코드 페이지 1253은 그리스어 쓰기 시스템에 필요한 문자 코드를 제공합니다. 코드 페이지 1253의 마지막 128개 코드 포인트에는 그리스 문자가 포함되어 있습니다. 따라서 ANSI 코드 페이지를 사용하는 애플리케이션은 참조된 코드 페이지를 나타내는 식별자를 포함하지 않는 한 그리스어와 독일어를 동일한 텍스트 스트림에 저장할 수 없습니다.
DBCS(더블 바이트 문자 집합) 인코딩 256자를 초과하는 중국어, 일본어 및 한국어와 같은 언어를 지원합니다. DBCS에서 코드 포인트 쌍(더블 바이트)은 각 문자를 나타냅니다. Encoding.IsSingleByte 속성은 DBCS 인코딩에 대한 false 반환합니다. Encoding.GetEncoding(Int32) 메서드를 호출하여 특정 DBCS에 대한 인코딩 개체를 검색할 수 있습니다. 애플리케이션이 DBCS 데이터를 처리할 때 DBCS 문자의 첫 번째 바이트(리드 바이트)는 바로 뒤에 있는 후행 바이트와 함께 처리됩니다. 단일 쌍의 더블 바이트 코드 포인트는 코드 페이지에 따라 다른 문자를 나타낼 수 있으므로 이 체계는 동일한 데이터 스트림에서 일본어 및 중국어와 같은 두 언어의 조합을 허용하지 않습니다.

이러한 인코딩을 사용하면 레거시 애플리케이션에서 가장 일반적으로 사용되는 인코딩뿐만 아니라 유니코드 문자로 작업할 수 있습니다. 또한 Encoding 파생되는 클래스를 정의하고 해당 멤버를 재정의하여 사용자 지정 인코딩을 만들 수 있습니다.

.NET Core 인코딩 지원

기본적으로 .NET Core는 코드 페이지 28591 및 유니코드 인코딩(예: UTF-8 및 UTF-16) 이외의 코드 페이지 인코딩을 사용할 수 없습니다. 그러나 .NET을 대상으로 하는 표준 Windows 앱에 있는 코드 페이지 인코딩을 앱에 추가할 수 있습니다. 자세한 내용은 CodePagesEncodingProvider 항목을 참조하세요.

인코딩 클래스 선택

애플리케이션에서 사용할 인코딩을 선택할 기회가 있는 경우 유니코드 인코딩(UTF8Encoding 또는 UnicodeEncoding)을 사용해야 합니다. (.NET은 세 번째 유니코드 인코딩( UTF32Encoding.)도 지원합니다.

ASCII 인코딩(ASCIIEncoding)을 사용하려는 경우 대신 UTF8Encoding 선택합니다. 두 인코딩은 ASCII 문자 집합에 대해 동일하지만 UTF8Encoding 다음과 같은 이점이 있습니다.

  • 모든 유니코드 문자를 나타낼 수 있는 반면, ASCIIEncoding U+0000과 U+007F 사이의 유니코드 문자 값만 지원합니다.

  • 오류 검색 및 더 나은 보안을 제공합니다.

  • 가능한 한 빨리 조정되었으며 다른 인코딩보다 빨라야 합니다. 완전히 ASCII인 콘텐츠의 경우에도 UTF8Encoding 사용하여 수행되는 작업은 ASCIIEncoding수행되는 작업보다 빠릅니다.

레거시 애플리케이션에만 ASCIIEncoding 사용하는 것이 좋습니다. 그러나 레거시 애플리케이션의 경우에도 다음과 같은 이유로 UTF8Encoding 더 나은 선택일 수 있습니다(기본 설정 가정).

  • 애플리케이션에 엄격하게 ASCII가 아닌 콘텐츠가 있고 ASCIIEncoding인코딩하는 경우 각 비 ASCII 문자는 물음표(?)로 인코딩됩니다. 애플리케이션이 이 데이터를 디코딩하면 정보가 손실됩니다.

  • 애플리케이션에 엄격하게 ASCII가 아닌 콘텐츠가 있고 UTF8Encoding사용하여 인코딩하는 경우 ASCII로 해석되는 경우 결과를 이해할 수 없는 것처럼 보입니다. 그러나 애플리케이션이 UTF-8 디코더를 사용하여 이 데이터를 디코딩하는 경우 데이터는 왕복을 성공적으로 수행합니다.

웹 애플리케이션에서 웹 요청에 대한 응답으로 클라이언트로 전송된 문자는 클라이언트에 사용되는 인코딩을 반영해야 합니다. 대부분의 경우 사용자가 예상하는 인코딩에 텍스트를 표시하려면 HttpResponse.ContentEncoding 속성을 HttpRequest.ContentEncoding 속성에서 반환된 값으로 설정해야 합니다.

인코딩 개체 사용

인코더는 문자 문자열(가장 일반적으로 유니코드 문자)을 해당하는 숫자(바이트)로 변환합니다. 예를 들어 ASCII 인코더를 사용하여 유니코드 문자를 ASCII로 변환하여 콘솔에 표시할 수 있습니다. 변환을 수행하려면 Encoding.GetBytes 메서드를 호출합니다. 인코딩을 수행하기 전에 인코딩된 문자를 저장하는 데 필요한 바이트 수를 확인하려면 GetByteCount 메서드를 호출할 수 있습니다.

다음 예제에서는 단일 바이트 배열을 사용하여 두 개의 별도 작업에서 문자열을 인코딩합니다. 다음 ASCII로 인코딩된 바이트 집합에 대한 바이트 배열의 시작 위치를 나타내는 인덱스를 유지 관리합니다. 바이트 배열이 인코딩된 문자열을 수용할 수 있을 만큼 충분히 큰지 확인하기 위해 ASCIIEncoding.GetByteCount(String) 메서드를 호출합니다. 그런 다음 ASCIIEncoding.GetBytes(String, Int32, Int32, Byte[], Int32) 메서드를 호출하여 문자열의 문자를 인코딩합니다.

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($"   {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: {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.

디코더는 특정 문자 인코딩을 반영하는 바이트 배열을 문자 배열 또는 문자열의 문자 집합으로 변환합니다. 바이트 배열을 문자 배열로 디코딩하려면 Encoding.GetChars 메서드를 호출합니다. 바이트 배열을 문자열로 디코딩하려면 GetString 메서드를 호출합니다. 디코딩을 수행하기 전에 디코딩된 바이트를 저장하는 데 필요한 문자 수를 확인하려면 GetCharCount 메서드를 호출할 수 있습니다.

다음 예제에서는 세 개의 문자열을 인코딩한 다음 단일 문자 배열로 디코딩합니다. 디코딩된 다음 문자 집합에 대한 문자 배열의 시작 위치를 나타내는 인덱스를 유지 관리합니다. GetCharCount 메서드를 호출하여 문자 배열이 디코딩된 모든 문자를 수용할 수 있을 만큼 충분히 큰지 확인합니다. 그런 다음 ASCIIEncoding.GetChars(Byte[], Int32, Int32, Char[], Int32) 메서드를 호출하여 바이트 배열을 디코딩합니다.

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

Encoding 파생된 클래스의 인코딩 및 디코딩 메서드는 전체 데이터 집합에서 작동하도록 설계되었습니다. 즉, 인코딩 또는 디코딩할 모든 데이터가 단일 메서드 호출에 제공됩니다. 그러나 경우에 따라 스트림에서 데이터를 사용할 수 있으며 인코딩 또는 디코딩할 데이터는 별도의 읽기 작업에서만 사용할 수 있습니다. 이렇게 하려면 이전 호출에서 저장된 상태를 기억하기 위해 인코딩 또는 디코딩 작업이 필요합니다. EncoderDecoder 파생된 클래스의 메서드는 여러 메서드 호출에 걸쳐 있는 인코딩 및 디코딩 작업을 처리할 수 있습니다.

특정 인코딩에 대한 Encoder 개체는 해당 인코딩의 Encoding.GetEncoder 속성에서 사용할 수 있습니다. 특정 인코딩에 대한 Decoder 개체는 해당 인코딩의 Encoding.GetDecoder 속성에서 사용할 수 있습니다. 디코딩 작업의 경우 Decoder 파생된 클래스에는 Decoder.GetChars 메서드가 포함되지만 Encoding.GetString해당하는 메서드는 없습니다.

다음 예제에서는 유니코드 바이트 배열을 디코딩하기 위해 Encoding.GetString 메서드와 Decoder.GetChars 메서드를 사용하는 것의 차이점을 보여 줍니다. 이 예제에서는 일부 유니코드 문자가 포함된 문자열을 파일에 인코딩한 다음 두 디코딩 메서드를 사용하여 한 번에 10바이트를 디코딩합니다. 서로게이트 쌍은 10번째 및 11바이트에서 발생하므로 별도의 메서드 호출에서 디코딩됩니다. 출력에서 볼 수 있듯이 Encoding.GetString 메서드는 바이트를 올바르게 디코딩할 수 없으며 대신 U+FFFD(REPLACEMENT CHARACTER)로 바꿉니다. 반면에 Decoder.GetChars 메서드는 바이트 배열을 디코딩하여 원래 문자열을 가져올 수 있습니다.

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

대체 전략 선택

메서드가 문자를 인코딩하거나 디코딩하려고 하지만 매핑이 없는 경우 실패한 매핑을 처리하는 방법을 결정하는 대체 전략을 구현해야 합니다. 대체 전략에는 다음 세 가지 유형이 있습니다.

  • 가장 적합한 대체

  • 대체 백업

  • 예외 폴백

중요합니다

인코딩 작업에서 가장 일반적인 문제는 유니코드 문자를 특정 코드 페이지 인코딩에 매핑할 수 없는 경우에 발생합니다. 디코딩 작업에서 가장 일반적인 문제는 잘못된 바이트 시퀀스를 유효한 유니코드 문자로 변환할 수 없는 경우에 발생합니다. 이러한 이유로 특정 인코딩 개체에서 사용하는 대체 전략을 알아야 합니다. 가능하면 개체를 인스턴스화할 때 인코딩 개체에서 사용하는 대체 전략을 지정해야 합니다.

Best-Fit 대체

대상 인코딩에서 문자에 정확히 일치하는 항목이 없는 경우 인코더는 유사한 문자에 매핑할 수 있습니다. (가장 적합한 대체는 주로 디코딩 문제가 아닌 인코딩입니다. 유니코드에 성공적으로 매핑할 수 없는 문자가 포함된 코드 페이지는 거의 없습니다.) 가장 적합한 대체는 Encoding.GetEncoding(Int32)Encoding.GetEncoding(String) 오버로드에서 검색되는 코드 페이지 및 더블 바이트 문자 집합 인코딩의 기본값입니다.

비고

이론적으로 .NET(UTF8Encoding, UnicodeEncodingUTF32Encoding)에서 제공되는 유니코드 인코딩 클래스는 모든 문자 집합의 모든 문자를 지원하므로 가장 적합한 대체 문제를 제거하는 데 사용할 수 있습니다.

가장 적합한 전략은 코드 페이지에 따라 다릅니다. 예를 들어 일부 코드 페이지의 경우 전체 너비 라틴 문자는 더 일반적인 반자 라틴 문자에 매핑됩니다. 다른 코드 페이지의 경우 이 매핑이 수행되지 않습니다. 공격적인 베스트 핏 전략에서도 일부 인코딩의 일부 문자에는 상상할 수 있는 적합성이 없습니다. 예를 들어 중국어 표기법은 코드 페이지 1252에 대한 적절한 매핑이 없습니다. 이 경우 대체 문자열이 사용됩니다. 기본적으로 이 문자열은 단일 질문 표시(U+003F)에 불과합니다.

비고

최적 전략은 자세히 문서화되지 않습니다. 그러나 여러 코드 페이지는 유니코드 컨소시엄의 웹 사이트에 설명되어 있습니다. 매핑 파일을 해석하는 방법에 대한 설명은 해당 폴더의 readme.txt 파일을 검토하세요.

다음 예제에서는 코드 페이지 1252(서유럽 언어용 Windows 코드 페이지)를 사용하여 가장 적합한 매핑 및 단점을 보여 줍니다. Encoding.GetEncoding(Int32) 메서드는 코드 페이지 1252의 인코딩 개체를 검색하는 데 사용됩니다. 기본적으로 지원하지 않는 유니코드 문자에 가장 적합한 매핑을 사용합니다. 이 예제에서는 세 개의 비 ASCII 문자(CIRCLED LATIN CAPITAL LETTER S(U+24C8), SUPERSCRIPT FIVE(U+2075) 및 INFINITY(U+221E)를 공백으로 구분하여 포함하는 문자열을 인스턴스화합니다. 예제의 출력에서 볼 수 있듯이 문자열이 인코딩되면 세 개의 원래 비공간 문자가 물음표(U+003F), DIGIT FIVE(U+0035) 및 DIGIT EIGHT(U+0038)으로 바뀝니다. DIGIT EIGHT은 지원되지 않는 INFINITY 문자를 대체하지 않으며, QUESTION MARK는 원래 문자에 대한 매핑을 사용할 수 없음을 나타냅니다.

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

가장 적합한 매핑은 유니코드 데이터를 코드 페이지 데이터로 인코딩하는 Encoding 개체의 기본 동작이며 이 동작을 사용하는 레거시 애플리케이션이 있습니다. 그러나 대부분의 새 애플리케이션은 보안상의 이유로 가장 적합한 동작을 피해야 합니다. 예를 들어 애플리케이션은 가장 적합한 인코딩을 통해 도메인 이름을 배치해서는 안 됩니다.

비고

인코딩에 대한 사용자 지정 최적 대체 매핑을 구현할 수도 있습니다. 자세한 내용은 사용자 지정 대체 전략 구현 섹션을 참조하세요.

인코딩 객체의 기본 설정이 최적의 대체 옵션인 경우, Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) 또는 Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) 오버로드를 호출하여 Encoding 객체를 검색할 때 다른 대체 전략을 선택할 수 있습니다. 다음 섹션에는 코드 페이지 1252에 매핑할 수 없는 각 문자를 별표(*)로 바꾸는 예제가 포함되어 있습니다.

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

대체 대비책

문자가 대상 구성표에 정확히 일치하지 않지만 매핑할 수 있는 적절한 문자가 없는 경우 애플리케이션은 대체 문자 또는 문자열을 지정할 수 있습니다. 유니코드 디코더의 기본 동작으로, 디코딩할 수 없는 2 바이트 시퀀스를 REPLACEMENT_CHARACTER(U+FFFD)로 바꿉니다. 또한 인코딩하거나 디코딩할 수 없는 각 문자를 물음표로 바꾸는 ASCIIEncoding 클래스의 기본 동작이기도 합니다. 다음 예제에서는 이전 예제의 유니코드 문자열에 대한 문자 대체를 보여 줍니다. 출력에서 알 수 있듯이 ASCII 바이트 값으로 디코딩할 수 없는 각 문자는 물음표의 ASCII 코드인 0x3F 대체됩니다.

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에는 문자가 인코딩 또는 디코딩 작업에서 정확하게 매핑되지 않는 경우 대체 문자열을 대체하는 EncoderReplacementFallbackDecoderReplacementFallback 클래스가 포함됩니다. 기본적으로 이 대체 문자열은 물음표이지만 클래스 생성자 오버로드를 호출하여 다른 문자열을 선택할 수 있습니다. 일반적으로 대체 문자열은 단일 문자이지만 요구 사항은 아닙니다. 다음은 별표(*)를 대체 문자열로 사용하는 EncoderReplacementFallback 개체를 인스턴스화하여 코드 페이지 1252 인코더의 동작을 변경하는 예제입니다.

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

비고

인코딩에 대한 대체 클래스를 구현할 수도 있습니다. 자세한 내용은 사용자 지정 대체 전략 구현 섹션을 참조하세요.

물음표(U+003F) 외에도 유니코드 대체 문자(U+FFFD)는 일반적으로 대체 문자열로 사용되며, 특히 유니코드 문자로 변환할 수 없는 바이트 시퀀스를 디코딩하는 경우에 특히 유용합니다. 그러나 대체 문자열을 자유롭게 선택할 수 있으며 여러 문자를 포함할 수 있습니다.

예외 대체

인코더는 가장 적합한 대체 또는 대체 문자열을 제공하는 대신 문자 집합을 인코딩할 수 없는 경우 EncoderFallbackException throw할 수 있으며, 디코더는 바이트 배열을 디코딩할 수 없는 경우 DecoderFallbackException throw할 수 있습니다. 인코딩 및 디코딩 작업에서 예외를 throw하려면 EncoderExceptionFallback 개체와 DecoderExceptionFallback 개체를 각각 Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) 메서드에 제공합니다. 다음 예제에서는 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 {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.

비고

인코딩 작업에 대한 사용자 지정 예외 처리기를 구현할 수도 있습니다. 자세한 내용은 사용자 지정 대체 전략 구현 섹션을 참조하세요.

EncoderFallbackExceptionDecoderFallbackException 개체는 예외를 발생시킨 조건에 대한 다음 정보를 제공합니다.

EncoderFallbackExceptionDecoderFallbackException 개체는 예외에 대한 적절한 진단 정보를 제공하지만 인코딩 또는 디코딩 버퍼에 대한 액세스를 제공하지 않습니다. 따라서 인코딩 또는 디코딩 메서드 내에서 잘못된 데이터를 바꾸거나 수정하는 것을 허용하지 않습니다.

사용자 지정 대체 전략 구현

코드 페이지에서 내부적으로 구현되는 가장 적합한 매핑 외에도 .NET에는 대체 전략을 구현하기 위한 다음 클래스가 포함되어 있습니다.

또한 다음 단계를 수행하여 가장 적합한 대체, 대체 대체 또는 예외 대체를 사용하는 사용자 지정 솔루션을 구현할 수 있습니다.

  1. 인코딩 작업에 대한 EncoderFallback 및 디코딩 작업에 대한 DecoderFallback 클래스를 파생합니다.

  2. 인코딩 작업에 대한 EncoderFallbackBuffer 및 디코딩 작업에 대한 DecoderFallbackBuffer 클래스를 파생합니다.

  3. 예외 대체의 경우 미리 정의된 EncoderFallbackExceptionDecoderFallbackException 클래스가 요구 사항을 충족하지 않는 경우 Exception 또는 ArgumentException같은 예외 개체에서 클래스를 파생합니다.

EncoderFallback 또는 DecoderFallback에서 파생

사용자 지정 대체 솔루션을 구현하려면 인코딩 작업에 대한 EncoderFallback 및 디코딩 작업에 대한 DecoderFallback 상속하는 클래스를 만들어야 합니다. 이러한 클래스의 인스턴스는 Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) 메서드에 전달되며 인코딩 클래스와 대체 구현 간의 중개자 역할을 합니다.

인코더 또는 디코더에 대한 사용자 지정 대체 솔루션을 만들 때 다음 멤버를 구현해야 합니다.

EncoderFallbackBuffer 또는 DecoderFallbackBuffer에서 파생

사용자 지정 대체 솔루션을 구현하려면 인코딩 작업에 대해 EncoderFallbackBuffer에서 상속받는 클래스와 디코딩 작업에 대해 DecoderFallbackBuffer에서 상속받는 클래스를 각각 만들어야 합니다. 이러한 클래스의 인스턴스는 EncoderFallbackDecoderFallback 클래스의 CreateFallbackBuffer 메서드에 의해 반환됩니다. EncoderFallback.CreateFallbackBuffer 메서드는 인코더에서 인코딩할 수 없는 첫 번째 문자가 발견되면 호출되고 디코더에서 디코딩할 수 없는 바이트가 하나 이상 발견되면 DecoderFallback.CreateFallbackBuffer 메서드가 호출됩니다. EncoderFallbackBufferDecoderFallbackBuffer 클래스는 대체 구현을 제공합니다. 각 인스턴스는 인코딩할 수 없는 문자 또는 디코딩할 수 없는 바이트 시퀀스를 대체할 대체 문자가 포함된 버퍼를 나타냅니다.

인코더 또는 디코더에 대한 사용자 지정 대체 솔루션을 만들 때 다음 멤버를 구현해야 합니다.

대체 구현이 최적 대체 또는 대체 대체(fallback)인 경우, EncoderFallbackBufferDecoderFallbackBuffer에서 파생된 클래스는 버퍼에 있는 정확한 문자 수와 반환할 다음 문자 인덱스를 나타내는 두 개의 프라이빗 인스턴스 필드를 유지 관리합니다.

EncoderFallback 예제

이전 예제는 대체 대체를 사용하여 ASCII 문자에 해당하지 않는 유니코드 문자를 별표(*)로 바꿉니다. 다음 예제에서는 대신 사용자 지정 최적 대체 구현을 사용하여 비 ASCII 문자의 더 나은 매핑을 제공합니다.

다음 코드는 비ASCII 문자의 최적 적합 매핑을 처리하기 위해 EncoderFallback로부터 파생된 CustomMapper 클래스를 정의합니다. 해당 CreateFallbackBuffer 메서드는 EncoderFallbackBuffer 구현을 제공하는 CustomMapperFallbackBuffer 개체를 반환합니다. CustomMapper 클래스는 Dictionary<TKey,TValue> 개체를 사용하여 지원되지 않는 유니코드 문자(키 값) 및 해당 8비트 문자(64비트 정수에 연속 2바이트로 저장됨)의 매핑을 저장합니다. 대체 버퍼에 이 매핑을 사용할 수 있도록 CustomMapper 인스턴스는 CustomMapperFallbackBuffer 클래스 생성자에 매개 변수로 전달됩니다. 가장 긴 매핑은 유니코드 문자 U+221E의 문자열 "INF"이므로 MaxCharCount 속성은 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

다음 코드는 EncoderFallbackBuffer파생되는 CustomMapperFallbackBuffer 클래스를 정의합니다. 가장 적합한 매핑을 포함하고 CustomMapper 인스턴스에 정의된 사전은 해당 클래스 생성자에서 사용할 수 있습니다. 해당 Fallback 메서드는 ASCII 인코더가 인코딩할 수 없는 유니코드 문자가 매핑 사전에 정의된 경우 true 반환합니다. 그렇지 않으면 false반환됩니다. 각 대체에 대해 private count 변수는 반환할 문자 수를 나타내고, private index 변수는 반환할 다음 문자의 문자열 버퍼( charsToReturn)의 위치를 나타냅니다.

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

그런 다음, 다음 코드는 CustomMapper 개체를 인스턴스화하고 인스턴스를 Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) 메서드에 전달합니다. 출력은 가장 적합한 대체 구현이 원래 문자열의 ASCII가 아닌 세 문자를 성공적으로 처리했음을 나타냅니다.

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

참고하십시오