LoginSignup
12
6

More than 5 years have passed since last update.

全角文字・半角文字の相互変換

Last updated at Posted at 2014-12-10

アンケートで集めたローマ字が全半角混在

ということはないだろうか。同じ人が混ぜて使うことはないと思うが、人により、アンケートフォームに全角文字で入力したり半角文字で入力したり……。このようなテキストファイルから特定の人をgrep検索するのは大変面倒臭い。

tomitaさんっているかなと思ったら、“tomita”、"tomita"、いや先頭を大文字に、あるいは苗字を全部大文字にする人もいるから“Tomita”、"Tomita"、“TOMITA”、"TOMITA"……、と6通りくらい試さなければならない。半角文字なら大文字・小文字を区別しないこともできるけど、全角文字ではそうはいかない。

というわけで「半角文字に変換したい」と思った。さてどうやるか?

正攻法でやる

やっぱ正攻法でしょ。

テキストデータを1バイトずつ読み、各文字が何バイト使っているのかを認識しながら読み進めていく。
その際、半角文字に変換可能な文字に遭遇した場合は置換する。

というわけで、そんな正攻法で作られたのがこのコマンド。→han
ついでに、全角へ変換するコマンドもある。→zen

これらのコマンドは、Open usp Tukubaiというシェルスクリプト開発者向けコマンドセットに収録されているものを、POSIX原理主義に基づいてシェルスクリプト+UNIXコマンドに移植したものだ。

使用例

例えば、次のようなテキストファイルがあったとする。

enquete.txt
#name                 ans1  ans2
Mogami          yes   no
Kaga                  no    yes
fubuki                yes   yes
mutsu            no    no
Shimakaze    no    yes

アンケート回答がまとまっているのだが、回答者によって自分の名前を全角で打ち込んだり半角で打ち込んだり、まちまちというわけだ。回答者名で検索したいとなった時、検索する側はいちいち大文字・小文字や全角・半角を区別したくない。このよう時に、hanコマンドを使うのである。

次のようにしてhanコマンドに掛けた後、trコマンドで大文字を全て小文字に変換する(その後でAWKに掛けているのは見やすさのためだ)。

$ ./han enquete.txt | tr A-Z a-z | awk '{printf("%-10s %-4s %-4s\n",$1,$2,$3);}'
#name      ans1 ans2
mogami     yes  no
kaga       no   yes
fubuki     yes  yes
mutsu      no   no
shimakaze  no   yes
$ 

こうしておけば、半角英数字で簡単に回答者名のgrep検索が可能だ。

尚、このhanコマンドはUTF-8のテキストにしか対応しておらず、JISやShitf JIS、EUC-JPテキストには対応していない。そのような文字を扱いたい場合は、iconvコマンドを用いたり、nkfコマンド(POSIXではないが)を用いて予めUTF-8に変換しておくこと。

全角への変換

半角から全角への変換をしたい場合は、zenというコマンドを使う。ちなみにこちらには、-kというオプションがあって、これを付けると半角カタカナのみ全角変換することができる。これはe-mail送信用のテキストファイルを作る際に有用だ。あとの使い方はhanと同じ。標準出力または引数でファイルを喰わせるだけだ。

もう少し詳しく仕組みを解説

全角混じりのテキストだって取り扱いを諦めることはない。一文字一文字愚直に、変換可能なものを変換していけばいいだけだ。ただ、その際に問題になるのはマルチバイトの扱いである。1バイトずつ読んだ場合、それがマルチバイト文字の終端なのか、それとも途中なのかということを常に判断しなければならない。

han、zenコマンドは文字エンコードがUTF-8前提で作られているが、そのためにはUTF-8の各文字のバイト長を正しく認識しなければならない。その情報は、Wikipedia日本語版のUTF-8のページにも記載されている。1文字読み込んでみてそのキャラクターコードがどの範囲にあるかということを判定していくと、1バイトから6バイトの範囲で長さを決定することができる。han、zenにはそのようなルーチンが実装されている。

そして1文字分読み取った結果、それと対になる半角文字あるいは全角文字が存在する時は、元の文字ではなく用意していた対の文字を出力すればよい。この時もPOSIX版AWKがやっていることはとても単純だ。対になる文字を全てAWKの連想配列に登録しておき、要素が存在すれば代わりに出力しているに過ぎない。ただし、半角カタカナから全角カタカナへの変換の時には注意事項がある。それは濁点、半濁点の処理だ。例えば、半角の「ハ」の直後に半角の「゜」が連なっていたら「ハ゜」ではなくて「パ」に変換しなければならないので、「ハ」が来た時点ですぐに置換処理をしてはならずに次の文字を見てからにしなければならないのだ。

このようにやり方を聞いて「なんてベタな書き方だ」と笑うかもしれない。しかし速度の問題が生じない限り、プログラムはベタに書く方がいい。その方が、他人にとっても、そして将来の自分にとっても、メンテナンスしやすいプログラムになる。UNIX哲学の教義その1

Small is beautiful.

のとおりだ。

12
6
2

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
12
6