全角ひらがな⇔全角カタカナ⇔半角ｶﾀｶﾅ変換をするコードを書いた話

#はじめに
はじめまして、@satoshiks です。

今回Apps ScriptのAdvent calender2017の24日目に投稿させていただきました。

仕事やプライベートでGoogle Apps Scriptを書き続けていますが、まだまだ知らないことだらけです。
かつてGUIビルダーが存在していた時は、UIのパーツに直接プログラムを設定できるのが面白くて遊んでいましたが廃止となり、それでもUIを作るのが面白くてUi ServiceでいろいろUIを作ることにはまっていたらそれも廃止になり、何となくニッチな方向に傾倒している自分に気づきながら、その度に新しい技術や別の手段を使って試行錯誤をしています。

UIは今ではHTML Serviceを使ってHTML、CSS、JavaScriptで以前よりも書きやすくなりました。（当時けっこう必死で覚えたUi Serviceのpanelとかgridの知識は二度と使うことがないだろうなぁ）


さて今回エントリーさせていただいたのは、上で触れたUIとは全く関係ないのですが、ひらがな、カタカナ、半角ｶﾀｶﾅの相互変換をするプログラムを作るというものです。処理自体はJavaScriptですが、スプレッドシートのデータを使ってシートに入力するところでGoogle Apps Scriptを使っています。
Web上には他にもいろいろな方法で変換するコードがあるかと思いますが、配列で突き合わせて変換する方法を書きました。特に目新しいものではないと思いますが、Google Apps Scriptの実行方法と合わせて軽い感じで見ていただけたらと思います。

（ちょっと前に自分のブログで書いた内容を改めて書き直しました）

#本題に入ります
ひらがなとカタカナの相互変換をしたいと思ったときに、Web上で変換できる便利なツールは見つかりますが、手元のコードで実現したくなって書いたコードです。


ついでに半角ｶﾀｶﾅも変換しようとしたら思いのほか大変でやめようかと思いましたが、いろいろ試している内に上手く変換できたのでそれも含めてコード.gsに書きました。

半角ｶﾀｶﾅは濁点（゛）と半濁点（゜）が一文字として処理されてしまい、配列の番号がズレて上手くいかない。「ｶﾞ」は「ｶ」と「ﾞ」に分かれてしまうというハマりどころがありました。
それを解決するために、「ﾞ」や「゜」があったら前の文字と合体させてから処理するというひと手間を加えました。
これがなければコードをもっと短く書ける。
arrayにpushする処理が不要なのでhankanaの一覧と合わせて10行削れる。

文字コードで変換するやり方もあると思いますが、ここではすべての文字を配列で用意しておいて（var hira, kana, hankana）配列の中で一致するときの番号を見て変換するやり方を書きました。

コード.gsを実行すると以下のようなログが出力されます。

<img width="339" alt="スクリーンショット 2017-12-03 10.25.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/45849/ba43be02-d37d-4b4a-d602-8a375aab9254.png">



##書いたコード

```js:コード.gs 
var hira = ["あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ", "た", "ち", "つ", "て", "と", "な", "に", "ぬ", "ね", "の", "は", "ひ", "ふ", "へ", "ほ", "ま", "み", "む", "め", "も", "や", "ゆ", "よ", "ら", "り", "る", "れ", "ろ", "わ", "を", "ん", "が", "ぎ", "ぐ", "げ", "ご", "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "づ", "で", "ど", "ば", "び", "ぶ", "べ", "ぼ", "ぱ", "ぴ", "ぷ", "ぺ", "ぽ", "ぁ", "ぃ", "ぅ", "ぇ", "ぉ", "ゃ", "ゅ", "ょ", "っ", "ゔ"];
var kana = ["ア", "イ", "ウ", "エ", "オ", "カ", "キ", "ク", "ケ", "コ", "サ", "シ", "ス", "セ", "ソ", "タ", "チ", "ツ", "テ", "ト", "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "ヒ", "フ", "ヘ", "ホ", "マ", "ミ", "ム", "メ", "モ", "ヤ", "ユ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ワ", "ヲ", "ン", "ガ", "ギ", "グ", "ゲ", "ゴ", "ザ", "ジ", "ズ", "ゼ", "ゾ", "ダ", "ヂ", "ヅ", "デ", "ド", "バ", "ビ", "ブ", "ベ", "ボ", "パ", "ピ", "プ", "ペ", "ポ", "ァ", "ィ", "ゥ", "ェ", "ォ", "ャ", "ュ", "ョ", "ッ", "ヴ"];
var hankana = ["ｱ", "ｲ", "ｳ", "ｴ", "ｵ", "ｶ", "ｷ", "ｸ", "ｹ", "ｺ", "ｻ", "ｼ", "ｽ", "ｾ", "ｿ", "ﾀ", "ﾁ", "ﾂ", "ﾃ", "ﾄ", "ﾅ", "ﾆ", "ﾇ", "ﾈ", "ﾉ", "ﾊ", "ﾋ", "ﾌ", "ﾍ", "ﾎ", "ﾏ", "ﾐ", "ﾑ", "ﾒ", "ﾓ", "ﾔ", "ﾕ", "ﾖ", "ﾗ", "ﾘ", "ﾙ", "ﾚ", "ﾛ", "ﾜ", "ｦ", "ﾝ", "ｶﾞ", "ｷﾞ", "ｸﾞ", "ｹﾞ", "ｺﾞ", "ｻﾞ", "ｼﾞ", "ｽﾞ", "ｾﾞ", "ｿﾞ", "ﾀﾞ", "ﾁﾞ", "ﾂﾞ", "ﾃﾞ", "ﾄﾞ", "ﾊﾞ", "ﾋﾞ", "ﾌﾞ", "ﾍﾞ", "ﾎﾞ", "ﾊﾟ", "ﾋﾟ", "ﾌﾟ", "ﾍﾟ", "ﾎﾟ", "ｧ", "ｨ", "ｩ", "ｪ", "ｫ", "ｬ", "ｭ", "ｮ", "ｯ", "ｳﾞ"];
function hira_kana_hankana() {
  var text = "ﾃﾞｼﾞｬｳﾞｭ"; 
  var input = hankana;
  var output = hira;

  var result = "";
  var array = [];
  for (var i = 0; i < text.length; i++) {
    if (text[i] == "ﾞ" || text[i] == "ﾟ") {
      array[array.length - 1] = (text[i - 1] + text[i]);
    } else {
      array.push(text[i]);
    }
    Logger.log(array);
  }
  for (var j = 0; j < array.length; j++) {
    var index = input.indexOf(array[j]);
    if (index == -1) {
      result = result + array[j];
    } else {
      result = result + output[index];
    }
    Logger.log(result);
  }
  Logger.log(result)
}
```

###変換するテキストと変換前後の文字の設定

var text = "ﾃﾞｼﾞｬｳﾞｭ"; 
var input = hankana;
var output = hira;

のところで

textに変換前のテキストを設定
inputに変換前の文字の種類（ひらがなならhira,カタカナならkana, 半角ｶﾀｶﾅならhankana）を設定
outputに変換後の文字の種類（同上）を設定

###コードを書く場所
今回はシートのデータを使うため、スプレッドシートのスクリプトエディタを使います。<br>
スプレッドシートの上の方にあるメニューに「ツール」があるので、それをクリックすると「スクリプトエディタ…」というのがあり、それを選択するとコード.gsというファイルが開きます。上のコードで上書きして実行メニューの関数を実行の中のhira_kana_hankana()を選択すると実行できます。

スプレッドシート
メニュー＞ツール＞スクリプトエディタ…

スクリプトエディタ
コード.gsを書いて保存＞メニュー＞関数を実行＞hira_kana_hankana()


#シートに入力する 

上のコードを改造して、スプレッドシートに変換結果を書き出すコードも書きました。


この例ではA列のひらがなをあらかじめ入力しておき、set_values()を実行すると、B列にカタカナ変換された文字が入力され、C列に半角ｶﾀｶﾅ変換された文字が入力されます。

このように
<img width="353" alt="スクリーンショット 2017-12-03 10.48.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/45849/49169033-df4f-0fd3-0523-ec2830b524ed.png">


```js:コード.gs 
function set_values(){
  var sh = SpreadsheetApp.getActiveSheet();
  var lastrow = sh.getLastRow();
  var range = sh.getRange("A2:A" + lastrow);
  var values = range.getValues();  
  for(var i = 0; i < values.length; i++){
     var row = i + 1;
     var kana_result = hira_kana_hankana(hira, kana, values[i][0]);
     var hankana_result = hira_kana_hankana(hira, hankana, values[i][0]);
     sh.getRange("B" + (row + 1)).setValue(kana_result);
     sh.getRange("C" + (row + 1)).setValue(hankana_result);
  } 
}

var hira = ["あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ", "た", "ち", "つ", "て", "と", "な", "に", "ぬ", "ね", "の", "は", "ひ", "ふ", "へ", "ほ", "ま", "み", "む", "め", "も", "や", "ゆ", "よ", "ら", "り", "る", "れ", "ろ", "わ", "を", "ん", "が", "ぎ", "ぐ", "げ", "ご", "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "づ", "で", "ど", "ば", "び", "ぶ", "べ", "ぼ", "ぱ", "ぴ", "ぷ", "ぺ", "ぽ", "ぁ", "ぃ", "ぅ", "ぇ", "ぉ", "ゃ", "ゅ", "ょ", "っ", "ゔ"];
var kana = ["ア", "イ", "ウ", "エ", "オ", "カ", "キ", "ク", "ケ", "コ", "サ", "シ", "ス", "セ", "ソ", "タ", "チ", "ツ", "テ", "ト", "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "ヒ", "フ", "ヘ", "ホ", "マ", "ミ", "ム", "メ", "モ", "ヤ", "ユ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ワ", "ヲ", "ン", "ガ", "ギ", "グ", "ゲ", "ゴ", "ザ", "ジ", "ズ", "ゼ", "ゾ", "ダ", "ヂ", "ヅ", "デ", "ド", "バ", "ビ", "ブ", "ベ", "ボ", "パ", "ピ", "プ", "ペ", "ポ", "ァ", "ィ", "ゥ", "ェ", "ォ", "ャ", "ュ", "ョ", "ッ", "ヴ"];
var hankana = ["ｱ", "ｲ", "ｳ", "ｴ", "ｵ", "ｶ", "ｷ", "ｸ", "ｹ", "ｺ", "ｻ", "ｼ", "ｽ", "ｾ", "ｿ", "ﾀ", "ﾁ", "ﾂ", "ﾃ", "ﾄ", "ﾅ", "ﾆ", "ﾇ", "ﾈ", "ﾉ", "ﾊ", "ﾋ", "ﾌ", "ﾍ", "ﾎ", "ﾏ", "ﾐ", "ﾑ", "ﾒ", "ﾓ", "ﾔ", "ﾕ", "ﾖ", "ﾗ", "ﾘ", "ﾙ", "ﾚ", "ﾛ", "ﾜ", "ｦ", "ﾝ", "ｶﾞ", "ｷﾞ", "ｸﾞ", "ｹﾞ", "ｺﾞ", "ｻﾞ", "ｼﾞ", "ｽﾞ", "ｾﾞ", "ｿﾞ", "ﾀﾞ", "ﾁﾞ", "ﾂﾞ", "ﾃﾞ", "ﾄﾞ", "ﾊﾞ", "ﾋﾞ", "ﾌﾞ", "ﾍﾞ", "ﾎﾞ", "ﾊﾟ", "ﾋﾟ", "ﾌﾟ", "ﾍﾟ", "ﾎﾟ", "ｧ", "ｨ", "ｩ", "ｪ", "ｫ", "ｬ", "ｭ", "ｮ", "ｯ", "ｳﾞ"];
function hira_kana_hankana(input, output, text) {
  var result = "";
  var array = [];
  for (var i = 0; i < text.length; i++) {
    if (text[i] == "ﾞ" || text[i] == "ﾟ") {
      array[array.length - 1] = (text[i - 1] + text[i]);
    } else {
      array.push(text[i]);
    }
  }
  for (var j = 0; j < array.length; j++) {
    var index = input.indexOf(array[j]);
    if (index == -1) {
      result = result + array[j];
    } else {
      result = result + output[index];
    }
  }
  return result;
}
```

###変換するテキストと変換前後の文字の設定

####ひらがな変換
var kana_result = hira_kana_hankana(hira, kana, values[i][0]);

ここで変換前はひらがな(hira)で、変換後はカタカナ(kana)で、A列で取得した一行ごとのテキストvalues[i][0]をhira_kana_hankanaに渡して結果を取得しています

<br>
####半角ｶﾀｶﾅ変換
var hankana_result = hira_kana_hankana(hira, hankana, values[i][0]);

ひらがな変換と同様に、変換前はひらがなで、変換後は半角ｶﾀｶﾅで、A列で取得した一行ごとのテキストを渡して結果を取得しています

###スクリプトを実行するときの許可について
set_values()を実行する際に以下のような許可を求められます
このあたりのフローは最近何度か変更が入っているようなのでまだ変わる可能性があります。
ここでは2017/12/24現在のフローを書きます。
<br>
####まずは関数を実行するフロー

スプレッドシート＞ツール＞スクリプトエディタ...＞コード.gsを保存＞実行＞関数を実行＞set_values()
<br>
#####スクリプトエディタを選択
![スクリーンショット 2017-12-21 2.30.39.png](https://qiita-image-store.s3.amazonaws.com/0/45849/24a366b0-f52b-05fd-c04a-90b30c80c2ec.png)
<br>
#####実行する関数を選択
![スクリーンショット 2017-12-21 2.30.23.png](https://qiita-image-store.s3.amazonaws.com/0/45849/31bc61ad-aaae-d146-668f-831e476c2901.png)
<br>
####次に許可をするフロー
これが最近変わって「このアプリは確認されていません」という表示が出るようになって許可する手順が増えました
<br>
1. 「許可を確認」をクリック
![スクリーンショット 2017-12-19 8.38.57.png](https://qiita-image-store.s3.amazonaws.com/0/45849/9fc9a3ba-87db-c606-3cad-83037ce02d5b.png)
<br><br><hr>
2. 実行するアカウントを選択
![スクリーンショット 2017-12-19 8.41.49.png](https://qiita-image-store.s3.amazonaws.com/0/45849/e0c0f840-d0c1-9bae-3464-d9fbe1c1b2ad.png)
<br><br><hr>
3. 詳細をクリック
![スクリーンショット 2017-12-19 8.43.39.png](https://qiita-image-store.s3.amazonaws.com/0/45849/a89ab9e3-4b6e-18d3-c606-2804074e0641.png)
<br><br><hr>
4. プロジェクト名をクリック
![スクリーンショット 2017-12-19 8.48.35.png](https://qiita-image-store.s3.amazonaws.com/0/45849/e23e95e8-e642-bb66-f83a-b0fe8fd97125.png)
<br><br><hr>
5. 許可をクリック
![スクリーンショット 2017-12-19 8.49.41.png](https://qiita-image-store.s3.amazonaws.com/0/45849/37ab7747-e0cf-735b-0a84-8430a5b790b8.png)



#おわりに
今回はJavaScriptで全角ひらがな⇔全角カタカナ⇔半角ｶﾀｶﾅ変換をするコードを書いて、それをスプレッドシートで利用するという内容で書いてみました。

どういう書き方が本当に正しいのか未だによくわかりませんが、とにかく想像したとおりに動くものを作りたくて、無駄なコードもいっぱい書きながら試行錯誤をしている真っ只中です。

Google Apps Scriptで試行錯誤しているコードを以下のブログで書いています。
http://www.pre-practice.net/p/contents.html

まとまった情報を整理したいと思いながら、部分的な情報を随時追加しています。