KAKEHASHI Tech Blog

カケハシのEngineer Teamによるブログです。

文字コードの世界の第一歩

こんにちは、株式会社カケハシでおくすり連絡帳 Pocket Musubiの開発を担当している渡辺です。

今回は文字コードについての記事を書きました。 Pocket Musubiではお薬手帳用QRコードを読み込み、デコードした結果を利用します。ここでデコードするときにうまくいかないケースがあり、そこでの知見です。

文字コードについて

蛇足ですが、文字コードについて簡単におさらいします。 文字コードとは、文字をコンピューターで扱うために、文字ごと割り当てた数字のことです。 文字コードの対応表に基づいて、文字を数字に割り当てることを文字エンコードと言います。 文字コードの対応表には、ASCIIやUTF-8のような規格があります。 たとえば、アルファベットを扱うASCII文字だと'a' は97番、'b'は98番と割り当てられています。

ASCII

先ほども出てきた「ASCII」とは、文字コードの標準規格です。 アルファベット[a-zA-Z]や数字[0-9]に記号や空白文字、それに制御文字を加えた128文字が規定されています。 ASCIIはすべて7ビットで表現できるので、1バイト以内で扱うことができます。

ASCII文字コード表

マルチバイト文字

ギリシャ文字やウムラウトがついた文字、 キリル文字やひらがな、カタカナ、漢字といったなどアルファベット以外の文字は ASCIIでは扱うことができません。 このようなアルファベットや数字以外の文字を扱うには1バイトでは足りず、2バイト以上で表す必要があります。そのため、いくつかの規格が生み出されました。

UTF-8

UTF-8はUnicode用の符号化方式の1つです。文字をコードポイントに変換し、UTF-8で16進数の符号に変換します。 1文字を1~4バイトの可変長で表現できます。 UTF-8はASCIIと互換性があり、ASCIIは1バイトですが、それ以外は2-4バイトで表現します。 UTF-8の場合、1バイトが1XXX XXXXと最初の1ビットが1ならば、ほぼ2バイト以上の文字を表すことになります。これは、文字が1バイトの場合はASCII文字であり、7ビットで表されるので最初の1ビットが必ず0になることを利用しています。

Shift_JIS

JIS規格として標準化された日本語を含むさまざまな文字を収録した文字コードです。 Shift_JISは日本語を扱うために生まれた文字コードで、UTF-8より扱う文字の数は少ないです。 日本語を扱う文字コードは上記以外にもEUC-JPISO-2022-JPがあります。

Shift_JISはJIS X 0201という一番古い日本語文字コード規格を元にしています。 JIS X 0201はASCIIで使わなかった8バイト目を利用して半角カナを実現しています。 は177番目(0xB1番目)となります。

JIS X 0201はカタカナで埋めた後に余りの領域があり、基本的にこの空いた領域を利用して、2バイトで日本語を利用しています。

Shift_JISの空いてる領域

お薬手帳のQRコード

お薬手帳のQRコードについても簡単に触れておきます。 お薬手帳はJAHISという団体が策定した仕様に基づいており、患者や処方薬の情報がCSVで記述されており、その文字列がQRコードにエンコードされています。 お薬手帳アプリはこのQRコードをデコードし、その文字列を利用しています。

お薬手帳の仕様書には、「CSV形式によるデータフォーマット仕様」の章に、ファイル形式はタグ形式のMS-DOS テキストファイル(ASCII またはShift_JIS データ)であるという記述があり、日本語はShift_JISで表されていることがわかります。

文字コードの判定について

Pocket MusubiのQRコードリーダーは、デコード対象の文字列の文字コードがわからない場合、最初の数バイトを読み込んで文字コードを推測していました。 実際に読み込んでみて、UTF-8かShift_JISかを、バイト列の特徴を見て判断します。

ここで注意しなければならない点があります。UTF-8において8バイト目が1の場合(0×80から0xFFまで)は2バイト文字になるという条件がありました。 しかし、Shift_JISでこの領域は半角カナの場合があります、この半角カナが原因で、Shift_JISをUTF-8と誤判定をしてしまうと場合がありました。*1

使用したQRコードリーダーのコードを見ると、UTF-8の判定が甘く、 Shift_JISもUTF-8と誤判定される確率が高いとわかりました。 ここの解析はとても苦労しました。

今回は現象が発生したケースのみ、Shift_JIS前提にデコードするように改変したライブラリを利用するようにしました。 仕様書にはShift_JISが前提とあるのがわかったので、十分検証して、すべてのケースに対してShift_JIS前提にデコードするように後に変更しました。

まとめ

今回は不具合が起きてしまったQRコードのデコード問題に関する文字コード(UTF-8/Shift_JIS)に絞って解説しました。 文字コードの世界は奥が深いうえに、さまざまなユースケースで必要とされます。今後も学び続けて知見を深めていきます。

カケハシではエンジニアとして一緒に学んでスキルアップできるエンジニアを募集しています。ぜひ興味あるほうはお声をかけてください。

*1:他にも原因があるので、半角カナがある=必ず文字化けするわけではない。今回文字コードに絞って解説している。