2016-11-17 12 views
0

ストリームまたはBinaryReaderから次のUTF8文字を読み取ろうとしています。動作しないもの:C#のストリームから単一のUTF8文字を読み取る

BinaryReader :: ReadChar - これは3バイトまたは4バイトの文字にスローされます。 2バイト構造を返すので、選択肢はありません。

BinaryReader :: ReadChars - 1文字を読み込むように要求した場合、3バイトまたは4バイトの文字が検出されると、これがスローされます。複数の文字を読むには、1文字以上を読むようにしてください。

StreamReader :: Read - これは、読み込むバイト数を知る必要がありますが、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- a-infinite-byte-stream-c-sharp –

+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]; 
} 
関連する問題