196の日記

セキュリティ系の勉強、その他開発メモとか雑談、忘れそうな計算式などを書き溜める場所になっています. githhubはUnity触っていた頃ものがメイン https://github.com/196kakinuma

【応用情報】Unicode -> UTF-8 -> 16進数表現の問題

問題

Unicode文字列をUTF-8エンコードすると、各文字の先頭バイトは2進数表示が0又は11で始まり、それ以降のバイトは10で始まる。16進数表示された次のデータは何文字のUnicode文字列をエンコードしたものか。

E3 83 9F E3 82 B9 E3 83 81 E3 83 AB 32 35 74 68


解き方

変換ツールを使えば一発ですが、それはダメです。まず、文字コードの仕様から見ます。

  • Unicode 世界各国の文字を統一して扱うための16bitコード。後に21bitに拡張された。
  • UTF-8 Unicode8bit単位で符号化するための文字符号化形式。ASCII文字と互換性をもち、ASCIIは0から始まる1byte文字で、それ以外の多バイト文字は、先頭バイト→11から始まる1byte、先頭以外のバイト→10から始まる1byteで符号化する。


ここで重要なのは、UTF-88bit文字ではないこと!!!僕は知りませんでした。笑 つまり1byteごとに区切ってちょうどいい大きさにするやつって感じですか。
ASCIIは7bit文字なので、必然的に1byte内に収まるんですね。一方Unicodeは2byte以上必要になるので、先頭バイトとそれ以外のバイトの始まりが分けられているんですかね?(多分)




文字だとわかりにくいので、図を用意。

f:id:thinline196:20180118172606j:plain:w300
Unicode->UTF8->16進数




改めて問題を確認。

問題文の最初の部分はエンコード後の先頭バイトについて。わざわざ書いてくれていました。優しい!
次に問題の文字列を確認。16進数が並んでいますね。これは、UTF-8を2進数→16進数に直した結果でしょうか。直し方の手順としては、

  • UTF-8から1byte分持ってくる(これで一文字とは限らない) 11100011
  • 4bitごとに分ける  1110 0011
  • 16進数に変換する  E3

こんな感じです。



手順がわかったところで、次は文字の切れ目の目安である、先頭byteが0又は11の探し方です。
2桁で表されている16進数の左側に先頭byteの情報が反映されるため、ここを確認すれば見つけ出すことができます。

  • 先頭が0から始まる4bitは 0000~0111 これを16進数に直すと0~7
  • 先頭が11から始まる4bitは 1100~1111  これを16進数に直すとC~F


つまり、2桁の左側が上の数字から始まっていれば、そこは先頭byteであり、文字の始まりであると言えそうです。
(余談ですが、先頭バイト以外は10で始まると言いましたが、これは16進数でいう8~Bにあたり、見事被らないですね)



あとは、問題から上の条件で始まる16進数を見つけ、数えればそれが答えです。



(E3 83 9F) (E3 82 B9) (E3 83 81) (E3 83 AB) (32) (35) (74) (68)

A.8文字







ところでなんて書いてあるのでしょうね。
以上。