2015年01月11日

C#でUTF-16をUTF-8に変換

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その61

■問題 (出題者:greentea さん)
UTF-16の文字コードを16進(1オクテットごとにスペース区切り)の形で入力します。入力した文字コードを、2進数の形(1オクテットごとにスペース区切り)で出力してください。 入力する文字コードはUCS-2の範囲(サロゲートペアを使わなくてもよい範囲)のみに限定しても構いませんが、可能ならばサロゲートペアにも対応したものに挑戦してください。
     * 例1: abc(U+0041 U+0042 U+0043)

          * 入力 00 41 00 42 00 43
          * 出力 01000001 01000010 01000011

     * 例2: あいう(U+3042 U+3044 U+3046)

          * 入力 30 42 30 44 30 46
          * 出力 11100011 10000001 10000010 11100011 10000001 10000100 11100011 10000001  10000110
正攻法からトリッキーな手段まで、いろいろお待ちしております。 参考: 通信用語の基礎知識 UTF-8


出題例から、出力は、UTF-8形式に直したものを2進形式で出力するということだと理解しました。 単に16進形式→2進形式ならば、UTF16と明示する必要がないですからね。

UTF16形式のバイト配列をUTF8形式のバイト配列に直接変換する方法が分からなかったので、 いったん文字列に変換後、UTF8に変換しています。

これらは、.NET Frameworkの機能を利用しているだけなので、ごりごり書かないといけないのは、 16進形式の文字列をbyte配列に変換するところだけです。これは、HexTextToBytes メソッドとして 実装しています。

お題は、2進数の形式で出力してくださいとのことですが、元がどんな文字列かが分かったほうが良いので、ついでに、文字列に変換したもの(上の例では「abc」「あいう」)も出力するようにしました。

サロゲートペアには対応してません。

using System;
using System.Collections.Generic;
using System.Text;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            PrintUtf16BEByBit("00 41 00 42 00 43");
            PrintUtf16BEByBit("30 42 30 44 30 46");
            PrintUtf16BEByBit("30 D7 30 ED 30 B0 30 E9 30 DF 30 F3 30 B0");
            Console.ReadKey();     
        }

         private static void PrintUtf16BEByBit(string hexText) {
            byte[] utf16 = HexTextToBytes(hexText);
            string s = Encoding.GetEncoding("UTF-16BE").GetString(utf16);
            Console.WriteLine(s);

            byte[] utf8 = Encoding.UTF8.GetBytes(s);
            foreach (var b in utf8) {
                Console.Write("{0} ", Convert.ToString(b, 2));
            }
            Console.WriteLine();
        }

        private static byte[] HexTextToBytes(string hexText) {
            hexText = hexText.Replace(" ", "");
            List<byte> list = new List<byte>();
            for (int i = 0; i < (hexText.Length / 2) * 2; i += 2) {
                string s = "" + hexText[i] + hexText[i + 1];
                list.Add(Convert.ToByte(s, 16));
            }
            return list.ToArray();
        }

    }
}


 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/52398637