pykakasiとMeCabを使ってモールス信号変換器を作る

CSGAdventCalendar 9日目
最近ラズパイを使ってモールス符号変換器を作ったので、備忘録。
![IMG_0956.JPG](https://qiita-image-store.s3.amazonaws.com/0/261202/32f8c862-e782-9bd3-4218-741f56c18189.jpeg)


# 概要
入力した文字列をモールス信号に変換、それをRaspberry PiのLEDを光らせて遊びました。
その際にpykakasiとMeCabを使ってアルゴリズムを組んだので備忘録です。
Githubの[リンク](https://github.com/Wisteria30/morseconv)も載せておきます。
環境はMac, python3.5.2です。

# モールス信号とは
> 文字や記号を表象する方法のひとつ。電信による伝達を目的として発明され、短点とその3倍の長さを持つ長点の組み合わせにより文字や記号を表す。ラテン文字を基礎とした国際モールス信号の他、和文モールス信号のように各国の文字に対応したモールス信号が考案されている。

みなさんご存知`SOS`のあれです。
日本語やアルファベットを「トン」「ツー」の二つの記号で表すことができます。
そんなモールス信号にもいくつかのルールがあります。

1. 長点1つは短点3つ分の長さ
2. 文字と文字の間には短点3つ分をあける
3. 単語と単語の間には短点7つ分あける

この他にも`SOS`は例外的に連続して打つなどルールはありますが、
今回は上記の3つをルールを中心にしていきます。

# やるべきこと
目標は日常的にSNSで書いている文章をモールス信号に変換できるようにすることです。
そのためにはやるべきことがいくつかあります。

1. 漢字をひらがなにする（漢字は変換できない）
    2. pykakasiを使って変換する
3. 自動的に単語で区切る（普通文章を書くときに単語では区切らない）
    4. MeCabを使って形態素解析で単語ごとに区切る
5. 変換のための条件分岐をひたすら書く

# pykakasi
pykakasiは日本語の漢字仮名交じり文を平仮名やローマ字綴りの文に変換するプログラム`KAKASI`のPythonバージョンです。
pipでインストールしてください。

```sh
$ pip install six semidbm
$ pip install pykakasi
```

私は下記のように使いました。
setModeの引数で変換の形を決めることができます。

```call.py
from pykakasi import kakasi
pic = "本日は晴天なり"
...
...
...
k = kakasi()
k.setMode("K", "H")  # カタカナをひらがなに
k.setMode("J", "H")  # 漢字をひらがなに
conv_k = k.getConverter()
pic = conv_k.do(pic)
print(pic) # ほんじつはせいてんなり
```

インストールや使い方は[公式のリポジトリ](https://github.com/miurahr/pykakasi)に載っています。

# MeCab
MeCabはオープンソースの形態素解析エンジンです。
Mecabを選んだ理由は下記の二つです。

1. 各種スクリプト言語でバインディングされていること
2. 他の形態素解析エンジンより高速であること

MeCabを使い、入力された文章を自動で単語に区切ります。
（正確にはMeCabは文章を形態素で区切るので、単語では区切りません。）
インストールはMeCab本体とその辞書、そしてPythonでバインディングしたライブラリを入れます。

```sh
$ brew install mecab #本体のインストール
$ brew install mecab-ipadic #辞書のインストール
$ pip install mecab-python3 #ライブラリのインストール
```

実際には下記のように使いました。

```call.py
import MeCab
pic = "本日は晴天なり"
try:
    m = MeCab.Tagger("-Owakati")
    pic = m.parse(pic)
    pic = pic.strip()  # 先頭と末尾の空白を削除
    pic = pic.replace(' ', '_')  # 単語間に開けた空白を変換
except RuntimeError:
    pic = ""
print(pic) #本日_は_晴天_なり
```

こちらは「[MeCab (和布蕪)とは](http://taku910.github.io/mecab/#install-unix)」と「[Python3からMeCabを使う](https://qiita.com/taroc/items/b9afd914432da08dafc8)」が参考になりました。

# 実際に使ってみる
上記のpykakasiとMeCabを使った変換器が下記のコードになります。
`import morse`はWeb上にあったモールス信号のコンバータを改変したものです。
コードは[こちら](https://github.com/Wisteria30/morseconv)にあります。

```call.py
# coding:utf-8
from pykakasi import kakasi, wakati
import MeCab
import morse


def convert(pic):
    pic = ''.join(pic.split())  # 空白の削除

    # MeCabによる形態素解析
    try:
        m = MeCab.Tagger("-Owakati")
        pic = m.parse(pic)
        pic = pic.strip()  # 先頭と末尾の空白を削除
        pic = pic.replace(' ', '_')  # 単語間に開けた空白を変換
    except RuntimeError:
        pic = ""

    # pykakasiによるカタカナ・漢字のひらがなへの変換

    k = kakasi()
    k.setMode("K", "H")  # カタカナをひらがなに
    k.setMode("J", "H")  # 漢字をひらがなに
    conv_k = k.getConverter()
    pic = conv_k.do(pic)

    context = ""
    for c in pic:
        context += c + "~"
    context.strip()

    ans = ""
    for c in context:
        ans += morse.s2m(c)

    return ans

```

これを下記のように実行させます。

```Main.py
import call

txt = "本日は晴天なり"
txt = call.convert(txt)
print(txt)
```

すると下記のようにちゃんと変換できているのがわかります。
`－・・　・－・－・　－－・－・　・・　・－－・　　　－・・・　　　・－－－・　・－　・－・－－　・－・－・　　　・－・　－－・`
後は、文字列で条件分岐をして光らせるなり音を鳴らす等すれば、完成です。


RaspberryPi LED発光のサンプル

```light.py
import RPi.GPIO as GPIO
import time
import call

# それぞれの処理の秒数
dot = 0.33333333  # トン
stick = dot*3  # ツー
space = dot*3  # 空白
between_sleep = dot/3 #「トン」と「ツー」の間の時間

txt = "本日は晴天なり"

# 光らせる
def light_up(sec):
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(23, GPIO.OUT)
    GPIO.output(23, GPIO.HIGH)
    time.sleep(sec)
    GPIO.cleanup()

# 光らせない(何もしない)
def light_down(sec):
    time.sleep(sec)
    pass

for c in call.convert(txt)
    if c == '・':
        light_up(dot) #1拍点灯
    if c == 'ー':
        light_up(stick) #3拍点灯
    if str[num] == '　':
        light_down(space) #3拍消灯
    time.sleep(between_sleep)
```

# まとめ
kakasiやMeCabといった既存の変換器を使うことで簡単にモールス信号変換器を作ることができました。
pykakasiのwakatiを使えばMeCabは必要なかったのですが、勉強のために色々触ってみました。
テキスト処理はしっかりしてるはずなので次はこれをAmazon EchoのSkillと組んで遊びたいです。