2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

rubyでJISコードを扱う

Posted at

やあ (´・ω・`)
ようこそ、バーボンハウスへ。
このテキーラはサービスだから、まず飲んで落ち着いて欲しい。

うん、「また」なんだ。済まない。
仏の顔もって言うしね、謝って許してもらおうとも思っていない。

でも、このタイトルを見たとき、君は、きっと言葉では言い表せない
「可能性」みたいなものを感じてくれたと思う。
全銀と戦うの中で、そういう気持ちを忘れないで欲しい
そう思って、この記事を書いたんだ。

じゃあ、注文を聞こうか。

JISコードはISO-2022-JPのこと?

ウィキペディアで「JISコード」を検索するとISO-2022-JPのページに飛ばされます。
しかし、文字コード表をみるとASCIIコードと半角カタカナのコードが重複しています。
例えば、「ア」だと0x31で「1」も0x31と表現しています。
0x311バイトだけだと「1」になるんですが、じゃあ、「ア」を表示したい場合はどうするかというと
エスケープシーケンスを使い0x1b284931〜として複数バイトを用いて表現します。
しかし、某全銀フォーマットだと1文字1バイトとなっているため、これだと半角カタカナ使えないじゃん、という話になります。

ここでちょっとコードを書いて確認してみましょう。

> require 'kconv'

> '1'.tojis.unpack('H*').join
=> "31"

次から、ちょっと想定と違ってきます。

> 'ア'.tojis.unpack('H*').join
=> "1b244225221b2842"

0x1b284931〜じゃないですね。じつは勝手に全角に変換しちゃってます。
※ちなみに、後ろ3バイトの0x1b2842は半角カタカナの終了(ASCIIの開始──ようするにコードエリアマップの切り替え用のエスケープシーケンス)

> 'ア'.tojis.unpack('H*').join
=> "1b244225221b2842"

なので、ドキュメントに書いてあるとおりにNKFで変換してみましょう。

> require 'nkf'

> NKF.nkf('-jxm0', 'ア').unpack('H*').join
=> "1b2849311b2842"

前と後ろの3バイト(0x1b28490x1b2842)はエスケープシーケンスなので残った0x31がISO-2022-JPの半角カタカナエリアマップにおける「ア」となり、やっと目的のバイトコードにたどり着きました。
が、1バイトどころか7バイトになってしまいます。

JISコードはJIS X0201のことだった

じゃあ、JISコード1バイトで半角カタカナを表示するにはどうすればいいのか?
最初にウィキペディアでJISコードを検索したのが罠で、
実は扱うべき文字コードはISO-2022-JPではなくJIS X0201が正しいのでした。
JIS X0201の文字コード表をみるとASCII文字と半角カタカナがちゃんと別のコードとしてマッピングされています。
この文字コードをRubyで扱うにはどうすればいいか?実際にコード上で確認してみましょう。

> NKF.nkf('-s -x -Z4', 'ア').unpack('H*').join
=> "b1"
> NKF.nkf('-s -x -Z4', 'ア').unpack('H*').join
=> "b1"

0xb1JIS X0201の文字コード表を確認すると、ちゃんと「ア」の文字コードとなっています。
NKFのオプションはそれぞれ

  • -s シフトJISに変換
  • -x 通常行われる半角カナから全角カナの変換を行わない(上記#tojisによる変換で半角カタカナが全角になっていたのはこれが原因)
  • -Z4 全角カナを半角カナに変換

という意味になります。
ちなみにここにあるスペースと¥マーク以外の記号は全角から半角のコードに変換してくれます。

これでJISコード1バイトで半角文字を扱うことができるようになりました。

JIS X0201はシフトJISの一部

NKFのオプションでシフトJISの変換を指定していましたが、
JIS X0201の文字コード表シフトJISの文字コード表を見比べるとASCII文字と半角カタカナのコードは同じだということがわかります。
「じゃあ結局、最初からSJISに変換するだけでよかったじゃん」となるところですが、そのとおりです。
ただ、Kconvによる変換だと、暗黙の半角→全角変換が行われ…

> 'ア'.tosjis.unpack('H*').join
=> "8341"
> 'ア'.tosjis.unpack('H*').join
=> "8341"

…となり、結局NKFを利用するところまでは必然となります。

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?