フォト
2017年9月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
無料ブログはココログ

« 豊四季 Tiny BASIC for Arduino STM32の動作テスト(2) - ゲームパッドの利用 | トップページ | 豊四季 Tiny BASIC for Arduino STM32の動作テスト(3) - LEDドットマトリックス »

2017年5月18日 (木)

Arduinoで半角カタカナのローマ字入力

Arduinoで半角カタカナのローマ字入力を行うプログラムを作成しました。
用途的にはArduino STM32用で稼働するTiny BASIC用ですが、Arduino UNOでも
利用出来ます。

01

パソコンの半角入力ではなく、Arduino側でローマ字を半角カタカナに変換して
出力した内容を表示しています。

半角カタカナを正しく表示するには、感じコードをSJIS設定する実用があります。

02

スケッチ
変換テーブルが大きです。
Arduino UNOではフラッシュメモリに配置等の工夫が必要ですね。

//
// ローマ字半角カタカナ入力
// 作成 2017/05/02 by たま吉さん
// 修正 2017/05/17,ltu(ッ)抜けの対応
//

#include <string.h>

#define RK_ENTRY_NUM (sizeof(RomaKama)/sizeof(RomaKama[0]))

//子音状態遷移コード
enum {
  _romaji_top = 0,
  _romaji_b, _romaji_c, _romaji_d, _romaji_f, _romaji_g,  _romaji_h, _romaji_j, _romaji_k, _romaji_l, _romaji_m,
  _romaji_n, _romaji_p, _romaji_q, _romaji_r, _romaji_s,  _romaji_t, _romaji_v, _romaji_w, _romaji_x, _romaji_y,
  _romaji_z, _romaji_by,_romaji_ch,_romaji_cy,_romaji_dh, _romaji_dw,_romaji_dy,_romaji_fw,_romaji_fy,_romaji_gw,
  _romaji_gy,_romaji_hy,_romaji_jy,_romaji_kw,_romaji_ky, _romaji_lt,_romaji_ly,_romaji_my,_romaji_ny,_romaji_py,
  _romaji_qw,_romaji_qy,_romaji_ry,_romaji_sh,_romaji_sw,_romaji_sy, _romaji_th,_romaji_ts,_romaji_tw,_romaji_ty,
  _romaji_vy,_romaji_wh,_romaji_xt,_romaji_xy,_romaji_zy,  
};

// カタカタ文字列変換テーブル
 const char RomaKama[][5][4]  =  {
  //  a       e       i       o        u
  { "\xb1", "\xb4", "\xb2", "\xb5", "\xb3", },                                          //[]  : ア エ イ オ ウ
  { "\xca\xde", "\xcd\xde", "\xcb\xde", "\xce\xde", "\xcc\xde", },                      //[b] : バ ベ ビ ボ ブ
  { "\xb6", "\xbe", "\xbc", "\xba", "\xb8", },                                          //[c] : カ セ シ コ ク
  { "\xc0\xde", "\xc3\xde", "\xc1\xde", "\xc4\xde", "\xc2\xde", },                      //[d] : ダ デ ヂ ド ヅ
  { "\xcc\xa7", "\xcc\xaa", "\xcc\xa8", "\xcc\xab", "\xcc", },                          //[f] : ファ フェ フィ フォ フ
  { "\xb6\xde", "\xb9\xde", "\xb7\xde", "\xba\xde", "\xb8\xde", },                      //[g] : ガ ゲ ギ ゴ グ
  { "\xca", "\xcd", "\xcb", "\xce", "\xcc", },                                          //[h] : ハ ヘ ヒ ホ フ
  { "\xbc\xde\xac", "\xbc\xde\xaa", "\xbc\xde", "\xbc\xde\xae", "\xbc\xde\xad", },      //[j] : ジャ ジェ ジ ジョ ジュ
  { "\xb6", "\xb9", "\xb7", "\xba", "\xb8", },                                          //[k] : カ ケ キ コ ク
  { "\xa7", "\xaa", "\xa8", "\xab", "\xa9", },                                          //[l] : ァ ェ ィ ォ ゥ
  { "\xcf", "\xd2", "\xd0", "\xd3", "\xd1", },                                          //[m] : マ メ ミ モ ム
  { "\xc5", "\xc8", "\xc6", "\xc9", "\xc7", },                                          //[n] : ナ ネ ニ ノ ヌ
  { "\xca\xdf", "\xcd\xdf", "\xcb\xdf", "\xce\xdf", "\xcc\xdf", },                      //[p] : パ ペ ピ ポ プ
  { "\xb8\xa7", "\xb8\xaa", "\xb8\xa8", "\xb8\xab", "\xb8", },                          //[q] : クァ クェ クィ クォ ク
  { "\xd7", "\xda", "\xd8", "\xdb", "\xd9", },                                          //[r] : ラ レ リ ロ ル
  { "\xbb", "\xbe", "\xbc", "\xbf", "\xbd", },                                          //[s] : サ セ シ ソ ス
  { "\xc0", "\xc3", "\xc1", "\xc4", "\xc2", },                                          //[t] : タ テ チ ト ツ
  { "\xb3\xde\xa7", "\xb3\xde\xaa", "\xb3\xde\xa8", "\xb3\xde\xab", "\xb3\xde", },      //[v] : ヴァ ヴェ ヴィ ヴォ ヴ
  { "\xdc", "\xb3\xaa", "\xb3\xa8", "\xa6", "\xb3", },                                  //[w] : ワ ウェ ウィ ヲ ウ
  { "\xa7", "\xaa", "\xa8", "\xab", "\xa9", },                                          //[x] : ァ ェ ィ ォ ゥ
  { "\xd4", "\xa8", "\xb2", "\xd6", "\xd5", },                                          //[y] : ヤ ィェ イ ヨ ユ
  { "\xbb\xde", "\xbe\xde", "\xbc\xde", "\xbf\xde", "\xbd\xde", },                      //[z] : ザ ゼ ジ ゾ ズ
  { "\xcb\xde\xac", "\xcb\xde\xaa", "\xcb\xde\xa8", "\xcb\xde\xae", "\xcb\xde\xad",},   //[by] : ビャ ビェ ビィ ビョ ビュ
  { "\xc1\xac", "\xc1\xaa", "\xc1", "\xc1\xae", "\xc1\xad", },                          //[ch] : チャ チェ チ チョ チュ
  { "\xc1\xac", "\xc1\xaa", "\xc1\xa8", "\xc1\xae", "\xc1\xad", },                      //[cy] : チャ チェ チィ チョ チュ
  { "\xc3\xde\xac", "\xc3\xde\xaa", "\xc3\xde\xa8", "\xc3\xde\xae", "\xc3\xde\xad", },  //[dh] : デャ デェ ディ デョ デュ
  { "\xc4\xde\xa7", "\xc4\xde\xaa", "\xc4\xde\xa8", "\xc4\xde\xab", "\xc4\xde\xa9", },  //[dw] : ドァ ドェ ドィ ドォ ドゥ
  { "\xc1\xde\xac", "\xc1\xde\xaa", "\xc1\xde\xa8", "\xc1\xde\xae", "\xc1\xde\xad", },  //[dy] : ヂャ ヂェ ヂィ ヂョ ヂュ
  { "\xcc\xa7", "\xcc\xaa", "\xcc\xa8", "\xcc\xab", "\xcc\xa9", },                      //[fw] : ファ フェ フィ フォ フゥ
  { "\xcc\xac", "\xcc\xaa", "\xcc\xa8", "\xcc\xae", "\xcc\xad", },                      //[fy] : フャ フェ フィ フョ フュ
  { "\xb8\xde\xa7", "\xb8\xde\xaa", "\xb8\xde\xa8", "\xb8\xde\xab", "\xb8\xde\xa9", },  //[gw] : グァ グェ グィ グォ グゥ
  { "\xb7\xde\xac", "\xb7\xde\xaa", "\xb7\xde\xa8", "\xb7\xde\xae", "\xb7\xde\xad", },  //[gy] : ギャ ギェ ギィ ギョ ギュ
  { "\xcb\xac", "\xcb\xaa", "\xcb\xa8", "\xcb\xae", "\xcb\xad", },                      //[hy] : ヒャ ヒェ ヒィ ヒョ ヒュ
  { "\xbc\xde\xac", "\xbc\xde\xaa", "\xbc\xde\xa8", "\xbc\xde\xae", "\xbc\xde\xad", },  //[jy] : ジャ ジェ ジィ ジョ ジュ
  { "\xb8\xa7", "\x00", "\x00", "\x00", "\x00", },                                      //[kw] : クァ NG NG NG NG
  { "\xb7\xac", "\xb7\xaa", "\xb7\xa8", "\xb7\xae", "\xb7\xad", },                      //[ky] : キャ キェ キィ キョ キュ
  { "\x00", "\x00", "\x00", "\x00", "\xaf", },                                          //[lt] : NG NG NG NG ッ
  { "\xac", "\xaa", "\xa8", "\xae", "\xad", },                                          //[ly] : ャ ェ ィ ョ ュ
  { "\xd0\xac", "\xd0\xaa", "\xd0\xa8", "\xd0\xae", "\xd0\xad", },                      //[my] : ミャ ミェ ミィ ミョ ミュ
  { "\xc6\xac", "\xc6\xaa", "\xc6\xa8", "\xc6\xae", "\xc6\xad", },                      //[ny] : ニャ ニェ ニィ ニョ ニュ
  { "\xcb\xdf\xac", "\xcb\xdf\xaa", "\xcb\xdf\xa8", "\xcb\xdf\xae", "\xcb\xdf\xad", },  //[py] : ピャ ピェ ピィ ピョ ピュ
  { "\xb8\xa7", "\xb8\xaa", "\xb8\xa8", "\xb8\xab", "\xb8\xa9", },                      //[qw] : クァ クェ クィ クォ クゥ
  { "\xb8\xac", "\xb8\xaa", "\xb8\xa8", "\xb8\xae", "\xb8\xad", },                      //[qy] : クャ クェ クィ クョ クュ
  { "\xd8\xac", "\xd8\xaa", "\xd8\xa8", "\xd8\xae", "\xd8\xad", },                      //[ry] : リャ リェ リィ リョ リュ
  { "\xbc\xac", "\xbc\xaa", "\xbc", "\xbc\xae", "\xbc\xad", },                          //[sh] : シャ シェ シ ショ シュ
  { "\xbd\xa7", "\xbd\xaa", "\xbd\xa8", "\xbd\xab", "\xbd\xa9", },                      //[sw] : スァ スェ スィ スォ スゥ
  { "\xbc\xac", "\xbc\xaa", "\xbc\xa8", "\xbc\xae", "\xbc\xad", },                      //[sy] : シャ シェ シィ ショ シュ
  { "\xc3\xac", "\xc3\xaa", "\xc3\xa8", "\xc3\xae", "\xc3\xad", },                      //[th] : テャ テェ ティ テョ テュ
  { "\xc2\xa7", "\xc2\xaa", "\xc2\xa8", "\xc2\xab", "\xc2", },                          //[ts] : ツァ ツェ ツィ ツォ ツ
  { "\xc4\xa7", "\xc4\xaa", "\xc4\xa8", "\xc4\xab", "\xc4\xa9", },                      //[tw] : トァ トェ トィ トォ トゥ
  { "\xc1\xac", "\xc1\xaa", "\xc1\xa8", "\xc1\xae", "\xc1\xad", },                      //[ty] : チャ チェ チィ チョ チュ
  { "\xb3\xde\xac", "\xb3\xde\xaa", "\xb3\xde\xa8", "\xb3\xde\xae", "\xb3\xde\xad", },  //[vy] : ヴャ ヴェ ヴィ ヴョ ヴュ
  { "\xb3\xa7", "\xb3\xaa", "\xb3\xa8", "\xb3\xab", "\xb3", },                          //[wh] : ウァ ウェ ウィ ウォ ウ
  { "\x00", "\x00", "\x00", "\x00", "\xaf", },                                          //[xt] : NG NG NG NG ッ
  { "\xac", "\xaa", "\xaa", "\xae", "\xad", },                                          //[xy] : ャ ェ ェ ョ ュ
  { "\xbc\xde\xac", "\xbc\xde\xaa", "\xbc\xde\xa8", "\xbc\xde\xae", "\xbc\xde\xad", },  //[zy] : ジャ ジェ ジィ ジョ ジュ
};

// 例外([nn])
const char RomaKama_nn[4]  ="\xdd"; // 'ン'

// 母音テーブル
const char BoonTable[]  = { 
  'a','e','i','o','u',
};

// 子音テーブル
const char ShionTable[]  = {
  'b' ,'c' ,'d' ,'f' ,'g' ,'h' ,'j' ,'k' ,'l' ,'m' ,'n' ,'p' ,'q' ,'r' ,'s' ,'t' ,'v' ,'w' ,'x' ,'y' ,'z',
};

// 2文字子音テーブル Xh系列
const char Shion_Xh_Table[][2]  = {
  { _romaji_c, _romaji_ch },{ _romaji_d, _romaji_dh },{ _romaji_s, _romaji_sh }, { _romaji_t, _romaji_th },
  { _romaji_w, _romaji_wh },  
};

// 2文字子音テーブル Xw系列
const char Shion_Xw_Table[][2]  = {
  { _romaji_d, _romaji_dw },{ _romaji_f, _romaji_fw },{ _romaji_g, _romaji_gw },{ _romaji_k, _romaji_kw }, 
  { _romaji_q, _romaji_qw },{ _romaji_s, _romaji_sw },{ _romaji_t, _romaji_tw }, 
};

// 2文字子音テーブル Xt系列
const char Shion_Xt_Table[][2]  = {
  {  _romaji_x, _romaji_xt } ,  {  _romaji_l, _romaji_lt } ,
};

// 2文字子音テーブル Xy系列
const char Shion_Xy_Table[][2]  = {
  { _romaji_b, _romaji_by },{ _romaji_c, _romaji_xy },{ _romaji_d, _romaji_dy },{ _romaji_f, _romaji_fy },
  { _romaji_g, _romaji_gy },{ _romaji_h, _romaji_hy },{ _romaji_j, _romaji_jy },{ _romaji_k, _romaji_ky },
  { _romaji_l, _romaji_ly },{ _romaji_m, _romaji_my },{ _romaji_n, _romaji_ny },{ _romaji_p, _romaji_py }, 
  { _romaji_q, _romaji_qy },{ _romaji_r, _romaji_ry },{ _romaji_s, _romaji_sy },{ _romaji_t, _romaji_ty },
  { _romaji_v, _romaji_vy },{ _romaji_x, _romaji_xy },{ _romaji_z, _romaji_zy }, 
};

int16_t romaji_sts = _romaji_top;  // 状態遷移コード
uint8_t flgTsu = false;            // 小さいツ付加フラグ
char kataStr[6];                   // 確定カタカナ文字列

// 文字コードから母音コード(0~4)に変換する
inline int16_t charToBoonCode(uint8_t c) {
  for (uint8_t i=0; i < sizeof(BoonTable); i++)
    if (c == BoonTable[i])
       return i;
  return -1;
}

// 文字コードから子音コードに変換する
inline int16_t charToShionCode(uint8_t c) {
  for (uint8_t i=0; i < sizeof(ShionTable); i++)
    if (c == ShionTable[i])
       return i+1;
  return -1;
}

// ローマ字カタカタ変換
// 直前の状態遷移から次の状態に遷移する
char* pRomaji2Kana(uint8_t c) {
  int16_t code;
  char*   ptr;

  // 小文字変換
  if (c >= 'A' && c <= 'Z')
    c = c - 'A' + 'a';

  // 文字範囲チェック
  // (後で長音・濁音・半濁音・句点・読点の許可する対応の追加)
  if (c < 'a' || c > 'z')
    goto STS_ERROR;
  
  code = charToBoonCode(c); // 母音チェック
  if (code >= 0) {
    // 母音の場合,文字列を確定する
    if (romaji_sts >= _romaji_top && romaji_sts <= _romaji_zy) {
      ptr = (char*)RomaKama[romaji_sts][code];
      goto STS_DONE;    // 変換完了
    } else
      goto STS_ERROR;  // 変換エラー
  } else {
    // 母音でない場合、子音コードを取得
    code = charToShionCode(c);
    if (code < 0) 
       goto STS_ERROR; // 子音でない(エラー)         
    if (romaji_sts == _romaji_top) {
      // 初期状態で子音コードなら次の状態に遷移
      romaji_sts = code;
      goto STS_NEXT;
    } else if (romaji_sts >= _romaji_b && romaji_sts <= _romaji_z) {
      // 1文字子音受理済みからの子音入力の対応
      if ( romaji_sts == code) {
        // 同じ子音が連続
        if (!flgTsu) {
           if (code == _romaji_n) {
             // nn('ン')の場合
             ptr = (char*)RomaKama_nn;
             goto STS_DONE;    // 変換完了             
           } else {
             flgTsu = true;  // 小さい'ツ'の先頭付加フラグの設定
             goto STS_NEXT;
           }
        } else
          // 既に小さい'ツ'の先頭付加フラグがセットされている場合はエラー
          goto STS_ERROR;
      } else {
        // 2文字子音への遷移チェック
        switch(code) {
        case _romaji_h:
          for (uint16_t i=0; i < (sizeof(Shion_Xh_Table)/sizeof(Shion_Xh_Table[0])); i++)
            if ( Shion_Xh_Table[i][0] == romaji_sts) {
              romaji_sts =  Shion_Xh_Table[i][1];
              goto STS_NEXT;
            }
          goto STS_ERROR;
        case _romaji_w:
          for (uint16_t i=0; i < (sizeof(Shion_Xw_Table)/sizeof(Shion_Xw_Table[0])); i++)
            if ( Shion_Xw_Table[i][0] == romaji_sts) {
              romaji_sts =  Shion_Xw_Table[i][1];
              goto STS_NEXT;
            }
          goto STS_ERROR;
        case _romaji_t:
          for (uint16_t i=0; i < (sizeof(Shion_Xt_Table)/sizeof(Shion_Xt_Table[0])); i++)
            if ( Shion_Xt_Table[i][0] == romaji_sts) {
              romaji_sts =  Shion_Xt_Table[i][1];
              goto STS_NEXT;
            }
          goto STS_ERROR;
        case _romaji_y:
          for (uint16_t i=0; i < (sizeof(Shion_Xy_Table)/sizeof(Shion_Xy_Table[0])); i++)
            if ( Shion_Xy_Table[i][0] == romaji_sts) {
              romaji_sts =  Shion_Xy_Table[i][1];
              goto STS_NEXT;
            }
          goto STS_ERROR;
        default:
          goto STS_ERROR;
        }     
      }
    }
  }
  
STS_NEXT:  // 次の状態へ
  return NULL;
  
STS_ERROR: // [状態遷移エラー]
  romaji_sts = _romaji_top;  // 状態の初期化
  flgTsu = false;            // 小さい'ツ'の先頭付加フラグクリア
  return NULL;
  
STS_DONE:  // [ローマ字カタカナ変換 遷移完了]
  if (flgTsu) {
    kataStr[0] = 0xaf; // 'ッ' の設定
    strcpy(kataStr+1, ptr);
    ptr = kataStr;
  }
  romaji_sts = _romaji_top;  // 状態の初期化
  flgTsu = false;            // 小さい'ツ'の先頭付加フラグクリア
  return ptr;

}

void setup() {
  Serial.begin(115200);
}

void loop() {
  char c;
  char* ptr;
  if (Serial.available()) {
    c = Serial.read();
    if (c == '\n') {
      Serial.println();
    } else {
      ptr = pRomaji2Kana(c);
      if (ptr) {
        Serial.print(ptr);
      }
    }
  }
}

スケッチの作成は次のような状態遷移表(クリックで拡大表示)をEXCELで作成し、
EXCELの関数やらを駆使してC言語用のテーブルを自動生成してます。
EXCELはプログラムを作成のツールとして重宝します。

03

一見、単純なローマ字 => 半角カタカナ 対応のテーブルを使った方が簡単と思ったのですが
意外と難しいく、1文字入力する都度、状況(状態)に応じて変換した方が楽でした。

例えば、"ガッチャマン"と入力する場合、
ローマ字入力では、gattyamann を入力しますが、
単純なローマ字、カタカナテーブルを使って行おうとすると
  ga    => ガ
 ttya  => ッチャ
 ma   => マ
  nn    => ン

のように、可変長文字列を切り出しにて検索する等、ちょと面倒になってきます。
その切り出し処理に、結局は状態の管理が必要になります。
入力された1文字づつ処理した方が単純になります。

« 豊四季 Tiny BASIC for Arduino STM32の動作テスト(2) - ゲームパッドの利用 | トップページ | 豊四季 Tiny BASIC for Arduino STM32の動作テスト(3) - LEDドットマトリックス »

arduino」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/571408/65295989

この記事へのトラックバック一覧です: Arduinoで半角カタカナのローマ字入力:

« 豊四季 Tiny BASIC for Arduino STM32の動作テスト(2) - ゲームパッドの利用 | トップページ | 豊四季 Tiny BASIC for Arduino STM32の動作テスト(3) - LEDドットマトリックス »