- <html>
-
- <head>
- <title>すすーっすっすーっっすっーっすすーっすっすっーっっすすーすっっすっーっすすっすーすっすすっーすすすっすーっすすすーっーっすっすっーっすっっーっすっすっーすすすっすーすっすすっーっすすっーすすすっすー</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
- </head>
-
- <body>
- <div>
- 原文<br />
- <div style="font-size: x-small;">
- 全角カタカナで入力してください<br />
- ひらがなからカタカナへの変換などは行いません。<br />
- 半角カナはサポートしていません。<br />
- </div>
- <textarea id="text" rows="10" cols="40">アンナチャン…</textarea><br />
- </div>
- <div>
- <button id="btn_encode">↓エンコード</button> <button id="btn_decode">↑デコード</button><br />
- </div>
- <div>
- ヨロモールス <button id="play" style="font-size: xx-small;">再生</button><br />
- <textarea id="yoro" rows="10" cols="40">ススッススーッスッスッーッスッーッッスッーッススーッスッスッー…</textarea><br />
- </div>
- <script>
- /**
- * @var Map<String, String> table カタカナとモールス信号の対照表。すっじゃなくて10で書いてるのは、単純に視認性が良かったから。
- */
- var table = {
- 'ア': '11011',
- 'カ': '0100',
- 'サ': '10101',
- 'タ': '10',
- 'ナ': '010',
- 'ハ': '1000',
- 'マ': '1001',
- 'ヤ': '011',
- 'ラ': '000',
- 'ワ': '101',
- 'イ': '01',
- 'キ': '10100',
- 'シ': '11010',
- 'チ': '0010',
- 'ニ': '1010',
- 'ヒ': '11001',
- 'ミ': '00101',
- 'リ': '110',
- 'ヰ': '01001',
- 'ウ': '001',
- 'ク': '0001',
- 'ス': '11101',
- 'ツ': '0110',
- 'ヌ': '0000',
- 'フ': '1100',
- 'ム': '1',
- 'ユ': '10011',
- 'ル': '10110',
- 'ン': '01010',
- 'オ': '01000',
- 'ケ': '1011',
- 'セ': '01110',
- 'テ': '01011',
- 'ネ': '1101',
- 'ヘ': '0',
- 'メ': '10001',
- 'レ': '111',
- 'ヱ': '01100',
- '、': '010101',
- 'エ': '10111',
- 'コ': '1111',
- 'ソ': '1110',
- 'ト': '00100',
- 'ノ': '0011',
- 'ホ': '100',
- 'モ': '10010',
- 'ヨ': '11',
- 'ロ': '0101',
- 'ヲ': '0111',
- '。': '010100',
- '0': '11111',
- '1': '01111',
- '2': '00111',
- '3': '00011',
- '4': '00001',
- '5': '00000',
- '6': '10000',
- '7': '11000',
- '8': '11100',
- '9': '11110',
- '゛': '00',
- 'ー': '01101',
- '゜': '00110',
- };
-
- /**
- * @var Map<String, String> revTable 逆検索用のテーブルを作ってキャッシュしたもの
- */
- var revTable = {};
- $.each(table, function (k, v) { revTable[v] = k; });
-
- $('#btn_encode').on('click', function () {
- // テキストを正規化する
- // 濁点と半濁点を分離。小音を普通の大きさにする。
- var text = $('#text').val();
- text = text.replace(/ガ/g, 'カ゛').replace(/ギ/g, 'キ゛').replace(/グ/g, 'ク゛').replace(/ゲ/g, 'ケ゛').replace(/ゴ/g, 'コ゛');
- text = text.replace(/ザ/g, 'サ゛').replace(/ジ/g, 'シ゛').replace(/ズ/g, 'ス゛').replace(/ゼ/g, 'セ゛').replace(/ゾ/g, 'ソ゛');
- text = text.replace(/ダ/g, 'タ゛').replace(/ヂ/g, 'チ゛').replace(/ヅ/g, 'ツ゛').replace(/デ/g, 'テ゛').replace(/ド/g, 'ト゛');
- text = text.replace(/バ/g, 'ハ゛').replace(/ビ/g, 'ヒ゛').replace(/ブ/g, 'フ゛').replace(/ベ/g, 'ヘ゛').replace(/ボ/g, 'ホ゛');
- text = text.replace(/バ/g, 'ハ゛').replace(/ビ/g, 'ヒ゛').replace(/ブ/g, 'フ゛').replace(/ベ/g, 'ヘ゛').replace(/ボ/g, 'ホ゛');
- text = text.replace(/ァ/g, 'ア').replace(/ィ/g, 'イ').replace(/ゥ/g, 'ウ').replace(/ェ/g, 'エ').replace(/ォ/g, 'オ');
- text = text.replace(/ッ/g, 'ツ').replace(/ャ/g, 'ヤ').replace(/ュ/g, 'ユ').replace(/ョ/g, 'ヨ').replace(/ヮ/g, 'ワ');
-
- // 1文字ずつ分離して処理する
- var yoro = '';
- $.each(text.split(''), function (pos, c) {
- var m = table[c];
- if (m == undefined) {
- // モールスに無い文字はそのまま書く
- m = c;
- } else {
- // 1101 => すすっすー
- m = m.replace(/1/g, 'す').replace(/0/g, 'っ');
- m += 'ー';
- }
- yoro += m;
- });
- $('#yoro').val(yoro);
- });
-
- $('#btn_decode').on('click', function () {
- var yoromors = $('#yoro').val();
- // ヨロモールス側は、カタカナ、ひらがな、半角カナを受け入れる
- // すすっすーっっすっー => 1101,0010
- var mors = yoromors.replace(/[すスス]/g, '1').replace(/[っッッ]/g, '0').replace(/[ー─-ー]/g, ',');
- var text = '';
-
- // 1グループごとに処理する
- $.each(mors.split(','), function (pos, mor) {
- // モールスパターンとの完全一致検索
- var c = revTable[mor];
-
- // 一致するものが無い場合は、モールスパターンをそのまま出す。
- if (c == undefined) c = mor;
-
- text += c;
- });
- $('#text').val(text);
- });
-
-
- /**
- * モールス信号再生
- * @see https://qiita.com/kurehajime/items/27c98de56fd06f93d0b8
- */
- var audio = new Audio();
- audio.src = 'http://xiidec.appspot.com/etc/pi.wav';
- $('#play').on('click', function () {
- // ヨロモールスを文字単位に分解
- var yoromors = $('#yoro').val().split('');
-
- // オーディオリセット
- audio.currentTime = 0;
-
- /**
- * @var Integer remain 次のオーディオ割り込みまでの残り周期
- */
- var remain = 0;
-
- /**
- * @var String mors モールスのグループを覚えておく変数。再生中の原文の逐次出力に使う。
- */
- var mors = '';
-
- // 50ミリ秒ごとに割り込み処理
- var timer = setInterval(function () {
- if (remain > 0) {
- // まだ割り込まない
- remain--;
- if (remain == 0) {
- audio.pause();
- audio.currentTime = 0;
- }
- return;
- }
-
- // オーディオを停止してリセット
- audio.pause();
- audio.currentTime = 0;
-
- if (yoromors.length <= 0) {
- // 終わり
- clearInterval(timer);
- return;
- }
-
- var onoff = yoromors.shift();
- $('#yoro').val($('#yoro').val() + onoff);
- if (onoff.match(/[すスス]/)) {
- // 長音を再生する
- audio.play();
- remain = 4;
- mors += '1';
- } else if (onoff.match(/[っッッ]/)) {
- // 単音を再生する
- audio.play();
- remain = 2;
- mors += '0';
- } else if (onoff.match(/[ー─-ー]/)) {
- // 区切りなので、再生せず無音を作る
- remain = 3;
-
- // 1グループ分のモールスをデコードして、原文テキストに追記
- $('#text').val($('#text').val() + revTable[mors]);
- mors = '';
- } else {
- // モールスとして解読できなかった文字はそのまま原文テキストに転記
- $('#text').val($('#text').val() + onoff);
- }
- }, 50);
- $('#text').val('');
- $('#yoro').val('');
- });
- </script>
- </body>
-
- </html>