Sample Site

GAWK カタカナ全角半角相互変換

「nkf」というコマンドラインプログラム(linux/Windows)を使用すれば、容易にカタカナの全角⇔半角変換が可能です。GAWK でもできると素敵ですので作ります。gsub() を使った例はネット上にいくつかあったので、違うアプローチで行きます。

何はともあれ、2つ辞書を作ります。1つ目は全角カタカナをキーとし、値を半角にしたもの。2つ目は半角カタカナをキーとして、値を全角にしたものを作ります。半角を全角に変換する場合、濁点「゙」や半濁点「゚」は1文字として数えられてしまうので、少し工夫が必要です。
全角から半角へ、半角から全角へ、それぞれの変換関数を間接的に呼び出します。「Indirect function call」GAWKではこう呼びます。アクション部で if や switch を使用しなくて済みますので、とても簡潔に書けます。

筆者の OS 環境が Linux 70%、Windows 30%と使用率が変化してしまい、とうとう WSL(Windows Subsystem for Linux) とWndows Terminal を導入してしまいました。バッチ処理は少しづつシェルスクリプトに変わり、このサイトでもコマンドプロンプトの使用が減っていくと思われます。

convkatakana.awk

注) GAWK ver.4 以降で動作します。

BEGIN
1 : BEGIN{ 2 : _convkatakana_init(); 3 : if(arg1 ~ /^\-z/) sw = "zen"; 4 : else sw = "han"; 5 : func_name["han"] = "convhan"; 6 : func_name["zen"] = "convzen"; 7 : call_func = func_name[sw]; 8 : }
ACTION_01
9 : { 10 : print @call_func($0); 11 : }
_convkatakana_init()
12 : function _convkatakana_init( i, zen, han, arzen, arhan){ 13 : zen = "ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポヴアイウエオ\ 14 : カキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロ\ 15 : ワヲンァィゥェォャュョッー"; 16 : split(zen, arzen, ""); 17 : han = "ガ,ギ,グ,ゲ,ゴ,ザ,ジ,ズ,ゼ,ゾ,ダ,ヂ,ヅ,デ,ド,バ,ビ,ブ,ベ,ボ,\ 18 : パ,ピ,プ,ペ,ポ,ヴ,ア,イ,ウ,エ,オ,カ,キ,ク,ケ,コ,サ,シ,ス,セ,ソ,タ,チ,ツ,テ,ト,ナ,ニ,ヌ,ネ,ノ,\ 19 : ハ,ヒ,フ,ヘ,ホ,マ,ミ,ム,メ,モ,ヤ,ユ,ヨ,ラ,リ,ル,レ,ロ,ワ,ヲ,ン,ァ,ィ,ゥ,ェ,ォ,ャ,ュ,ョ,ッ,ー"; 20 : split(han, arhan, ","); 21 : for(i in arzen) { 22 : _convhan[arzen[i]] = arhan[i]; 23 : _convzen[arhan[i]] = arzen[i]; 24 : } 25 : }
convhan()
26 : function convhan(str, i, ch, tstr) { 27 : while(ch = substr(str, ++i, 1)) 28 : if(ch in _convhan) tstr = tstr _convhan[ch]; 29 : else tstr = tstr ch; 30 : return tstr; 31 : }
convzen()
32 : function convzen(str, i, ch, ch2, tstr) { 33 : while(ch = substr(str, ++i, 1)) { 34 : ch2 = substr(str, i, 2); 35 : if(ch2 in _convzen) { tstr = tstr _convzen[ch2]; i++; } 36 : else if(ch in _convzen) tstr = tstr _convzen[ch]; 37 : else tstr = tstr ch; 38 : } 39 : return tstr; 40 : }

起動用コマンド名の登録(.bashrc)

300 : function convkatakana() { 301 : if [ -p /dev/stdin ]; then 302 : gawk -v arg1="$1" -f ~/awkf/convkatakana.awk 303 : elif [ $# -lt 1 ]; then 304 : echo "convkatakana: Not enough arguments" 305 : elif [ $# -lt 2 ]; then 306 : gawk -f ~/awkf/convkatakana.awk "$1" 307 : else 308 : gawk -v arg1="$1" -f ~/awkf/convkatakana.awk "$2" 309 : fi 310 : }

実行結果

$ echo '名言集1: オマエマルカジリ' | convkatakana 名言集1: オマエマルカジリ $ echo '名言集1: オマエマルカジリ' | convkatakana -z 名言集1: オマエマルカジリ

極稀に出現するカタカナを変換するのには向きませんが、カタカナしか出てこないデータに対しては普通に使えます。ランダムな姓名(全角カタカナ)1万データを半角カナ変換するのに、かかった時間は 40ms 逆は 84ms です。同データを「nkf」で処理すると、23ms と 25ms でしたので、大健闘といって過言ではないと思います。

余談ですが。「」、。・ たいていのプログラムがこれらの記号まで半角変換してしまいます。それ要らないんですけど、と思うのは筆者だけでしょうか。これらの記号を対象から除外するスイッチ等があるのかは、筆者の勉強不足で言及できませんが、このスクリプトはカタカナのみ変換します。

拡張機能として、数字やアルファベットの全半角変換、カタカナ全/半角から、ひらがなへの変換等、辞書を増やせば簡単に行えます。


おまけ LCD用半角カタカナ→コード変換

筆者は最近 Arduino というマイコンを始めました。液晶表示装置(LCD)で半角カタカナを表現するのに必要な変換が、上記のお題にピンポイントで合致しましたので作成します。(Linux)

Arduino IDE LCD用カタカナコード変換

lcdkana()  〜.bashrc
1 : function lcdkana() { 2 : arg="${@:$#:1}" 3 : gawk -v _arg="$arg" 'BEGIN{ 4 : st = _arg; 5 : lts = "ガ,ギ,グ,ゲ,ゴ,ザ,ジ,ズ,ゼ,ゾ,ダ,ヂ,ヅ,デ,ド,バ,ビ,ブ,ベ,ボ,\ 6 : パ,ピ,プ,ペ,ポ,ヴ,ア,イ,ウ,エ,オ,カ,キ,ク,ケ,コ,サ,シ,ス,セ,ソ,タ,チ,ツ,テ,ト,ナ,ニ,ヌ,ネ,ノ,\ 7 : ハ,ヒ,フ,ヘ,ホ,マ,ミ,ム,メ,モ,ヤ,ユ,ヨ,ラ,リ,ル,レ,ロ,ワ,ヲ,ン,ァ,ィ,ゥ,ェ,ォ,ャ,ュ,ョ,ッ,ー,、,。"; 8 : split(lts, arhfk, ","); 9 : lts = "\\xb6\\xde,\\xb7\\xde,\\xb8\\xde,\\xb9\\xde,\\xba\\xde,\ 10 : \\xbb\\xde,\\xbc\\xde,\\xbd\\xde,\\xbe\\xde,\\xbf\\xde,\ 11 : \\xc0\\xde,\\xc1\\xde,\\xc2\\xde,\\xc3\\xde,\\xc4\\xde,\ 12 : \\xca\\xde,\\xcb\\xde,\\xcc\\xde,\\xcd\\xde,\\xce\\xde,\ 13 : \\xca\\xdf,\\xcb\\xdf,\\xcc\\xdf,\\xcd\\xdf,\\xce\\xdf,\ 14 : \\xb3\\xde,\ 15 : \\xb1,\\xb2,\\xb3,\\xb4,\\xb5,\ 16 : \\xb6,\\xb7,\\xb8,\\xb9,\\xba,\ 17 : \\xbb,\\xbc,\\xbd,\\xbe,\\xbf,\ 18 : \\xc0,\\xc1,\\xc2,\\xc3,\\xc4,\ 19 : \\xc5,\\xc6,\\xc7,\\xc8,\\xc9,\ 20 : \\xca,\\xcb,\\xcc,\\xcd,\\xce,\ 21 : \\xcf,\\xd0,\\xd1,\\xd2,\\xd3,\ 22 : \\xd4,\\xd5,\\xd6,\ 23 : \\xd7,\\xd8,\\xd9,\\xda,\\xdb,\ 24 : \\xdc,\\xa6,\\xdd,\ 25 : \\xa7,\\xa8,\\xa9,\\xaa,\\xab,\ 26 : \\xac,\\xad,\\xae,\ 27 : \\xaf,-,\\xa4,\\xa1"; 28 : split(lts, arcod, ","); 29 : for(i in arhfk) _ck[arhfk[i]] = arcod[i]; 30 : print(_lcdkana(st)); 31 : } 32 : 33 : function _lcdkana(str, i, ch, ch2, tstr) { 34 : while(ch = substr(str, ++i, 1)) { 35 : ch2 = substr(str, i, 2); 36 : if(ch2 in _ck) { tstr = tstr _ck[ch2]; i++; } 37 : else if(ch in _ck) tstr = tstr _ck[ch]; 38 : else tstr = tstr ch; 39 : } 40 : return "lcd.print(\"" tstr "\");"; 41 : }' 42 : arg="" 43 : }
$ lcdkana 'オマエマルカジリ' lcd.print("\xb5\xcf\xb4\xcf\xd9\xb6\xbc\xde\xd8"); $ lcdkana 'happy set トイッショニビッグマックハイカガデスカ' lcd.print("happy set \xc4\xb2\xaf\xbc\xae\xc6\xcb\xde\xaf\xb8\xde\xcf\xaf\xb8\xca \xb2\xb6\xb6\xde\xc3\xde\xbd\xb6");

ターミナルを起動し、コマンドを打ち Arduino IDE へコピペします。ちょっと手間がかかりますが、 対照表を見ながら手打ちするよりは、幾ばくか早いと思います。
変換対照表は以下のHPを参考にさせていただきました。
もよいめもさん