CSGAdventCalendar 9日目
最近ラズパイを使ってモールス符号変換器を作ったので、備忘録。
概要
入力した文字列をモールス信号に変換、それをRaspberry PiのLEDを光らせて遊びました。
その際にpykakasiとMeCabを使ってアルゴリズムを組んだので備忘録です。
Githubのリンクも載せておきます。
環境はMac, python3.5.2です。
モールス信号とは
文字や記号を表象する方法のひとつ。電信による伝達を目的として発明され、短点とその3倍の長さを持つ長点の組み合わせにより文字や記号を表す。ラテン文字を基礎とした国際モールス信号の他、和文モールス信号のように各国の文字に対応したモールス信号が考案されている。
みなさんご存知SOS
のあれです。
日本語やアルファベットを「トン」「ツー」の二つの記号で表すことができます。
そんなモールス信号にもいくつかのルールがあります。
- 長点1つは短点3つ分の長さ
- 文字と文字の間には短点3つ分をあける
- 単語と単語の間には短点7つ分あける
この他にもSOS
は例外的に連続して打つなどルールはありますが、
今回は上記の3つをルールを中心にしていきます。
やるべきこと
目標は日常的にSNSで書いている文章をモールス信号に変換できるようにすることです。
そのためにはやるべきことがいくつかあります。
- 漢字をひらがなにする(漢字は変換できない)
2. pykakasiを使って変換する - 自動的に単語で区切る(普通文章を書くときに単語では区切らない)
4. MeCabを使って形態素解析で単語ごとに区切る - 変換のための条件分岐をひたすら書く
pykakasi
pykakasiは日本語の漢字仮名交じり文を平仮名やローマ字綴りの文に変換するプログラムKAKASI
のPythonバージョンです。
pipでインストールしてください。
$ pip install six semidbm
$ pip install pykakasi
私は下記のように使いました。
setModeの引数で変換の形を決めることができます。
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) # ほんじつはせいてんなり
インストールや使い方は公式のリポジトリに載っています。
MeCab
MeCabはオープンソースの形態素解析エンジンです。
Mecabを選んだ理由は下記の二つです。
- 各種スクリプト言語でバインディングされていること
- 他の形態素解析エンジンより高速であること
MeCabを使い、入力された文章を自動で単語に区切ります。
(正確にはMeCabは文章を形態素で区切るので、単語では区切りません。)
インストールはMeCab本体とその辞書、そしてPythonでバインディングしたライブラリを入れます。
$ brew install mecab #本体のインストール
$ brew install mecab-ipadic #辞書のインストール
$ pip install mecab-python3 #ライブラリのインストール
実際には下記のように使いました。
import MeCab
pic = "本日は晴天なり"
try:
m = MeCab.Tagger("-Owakati")
pic = m.parse(pic)
pic = pic.strip() # 先頭と末尾の空白を削除
pic = pic.replace(' ', '_') # 単語間に開けた空白を変換
except RuntimeError:
pic = ""
print(pic) #本日_は_晴天_なり
こちらは「MeCab (和布蕪)とは」と「Python3からMeCabを使う」が参考になりました。
実際に使ってみる
上記のpykakasiとMeCabを使った変換器が下記のコードになります。
import morse
はWeb上にあったモールス信号のコンバータを改変したものです。
コードはこちらにあります。
# 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
これを下記のように実行させます。
import call
txt = "本日は晴天なり"
txt = call.convert(txt)
print(txt)
すると下記のようにちゃんと変換できているのがわかります。
-・・ ・-・-・ --・-・ ・・ ・--・ -・・・ ・---・ ・- ・-・-- ・-・-・ ・-・ --・
後は、文字列で条件分岐をして光らせるなり音を鳴らす等すれば、完成です。
RaspberryPi LED発光のサンプル
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と組んで遊びたいです。