2016-11-17 3 views
0

스트림 또는 BinaryReader에서 다음 UTF8 문자를 읽으려고합니다. 작동하지 않는 것 :C#에서 스트림에서 단일 UTF8 문자 읽기

BinaryReader :: ReadChar - 3 바이트 또는 4 바이트 문자로 처리됩니다. 2 바이트 구조를 반환하기 때문에 선택의 여지가 없습니다.

BinaryReader :: ReadChars - 1 문자를 읽으라고 요청하면 3 바이트 또는 4 바이트 문자가 표시됩니다. 1 문자 이상을 읽으려면 여러 문자를 읽습니다.

읽기 - 바이트 수를 알아야하지만 UTF8 문자의 바이트 수는 가변적입니다.

나는 그것이 작동하는 것 같다 한 코드 : 분명히

private char[] ReadUTF8Char(Stream s) 
    { 
     byte[] bytes = new byte[4]; 
     var enc = new UTF8Encoding(false, true); 
     if (1 != s.Read(bytes, 0, 1)) 
      return null; 
     if (bytes[0] <= 0x7F) //Single byte character 
     { 
      return enc.GetChars(bytes, 0, 1); 
     } 
     else 
     { 
      var remainingBytes = 
       ((bytes[0] & 240) == 240) ? 3 : (
       ((bytes[0] & 224) == 224) ? 2 : (
       ((bytes[0] & 192) == 192) ? 1 : -1 
      )); 
      if (remainingBytes == -1) 
       return null; 
      s.Read(bytes, 1, remainingBytes); 
      return enc.GetChars(bytes, 0, remainingBytes + 1); 
     } 
    } 

, 이것은 혼란의 비트와 UTF8 다소 다릅니다. 이 문제에 대한 좀 더 우아하고, 사용자 정의가 덜하고, 읽기 쉬운 솔루션이 있습니까?

+0

의 가능한 중복 http://stackoverflow.com/questions/11671826/how-do-you-read-utf-8-characters-from- - 무한 바이트 - 스트림 - C - 샤프 –

+0

질문이 중복 될 수 있지만 그 대답은 작동하지 않습니다. 특히, 서로 게이트 쌍을 처리하지 않습니다. 나는 2 요소 char 버퍼를 사용하도록 수정하려고 시도했지만 다른 문제가 발생했습니다. 서로 게이트 쌍 이외의, 그것은 잘 작동합니다. – DDurschlag

+0

멋진데, 나는 똑같은지 100 % 확실하지는 않지만, 그것에 유용한 정보가있을 것이라고 생각했다. –

답변

0

나는이 질문이 약간 오래되었지만 여기에 또 다른 해결책이 있음을 알고있다. 그것은 내가 선호하는 OP 솔루션만큼 성능이 좋지는 않지만 utf8 인코딩 내부에 대해 알지 못하면서도 내장 utf8 기능 만 사용합니다.

private static char ReadUTF8Char(Stream s) 
{ 
    if (s.Position >= s.Length) 
     throw new Exception("Error: Read beyond EOF"); 

    using (BinaryReader reader = new BinaryReader(s, Encoding.Unicode, true)) 
    { 
     int numRead = Math.Min(4, (int)(s.Length - s.Position)); 
     byte[] bytes = reader.ReadBytes(numRead); 
     char[] chars = Encoding.UTF8.GetChars(bytes); 

     if (chars.Length == 0) 
      throw new Exception("Error: Invalid UTF8 char"); 

     int charLen = Encoding.UTF8.GetByteCount(new char[] { chars[0] }); 

     s.Position += (charLen - numRead); 

     return chars[0]; 
    } 
} 

BinaryReader의 생성자로 전달 된 인코딩은 중요하지 않습니다. 이 버전의 생성자를 사용하여 스트림을 열어 두어야했습니다. 이미 바이너리 독자가 있다면 당신은이를 사용할 수 있습니다

private static char ReadUTF8Char(BinaryReader reader) 
{ 
    var s = reader.BaseStream; 

    if (s.Position >= s.Length) 
     throw new Exception("Error: Read beyond EOF"); 

    int numRead = Math.Min(4, (int)(s.Length - s.Position)); 
    byte[] bytes = reader.ReadBytes(numRead); 
    char[] chars = Encoding.UTF8.GetChars(bytes); 

    if (chars.Length == 0) 
     throw new Exception("Error: Invalid UTF8 char"); 

    int charLen = Encoding.UTF8.GetByteCount(new char[] { chars[0] }); 

    s.Position += (charLen - numRead); 

    return chars[0]; 
}