##はじめに
この記事はRubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念の点字メーカープログラム作成したので、それについての解説記事です。
- 作成した人
- Ruby歴半年、今年6月からエンジニア転職を目指して毎日働きながら学習継続中
- 新卒で地元のメーカーに就職した社会人2年目の23歳
- なぜこちらの企画に参加したのか
- 伊藤さんのコードレビューを受けれるかもしれないから
- チェリー本を愛用しているため、形ある貢献がしたかったから
- Qiitaでアウトプットがしたかったから(初記事です)
- 完成したプログラムのプルリク↓
##お題の概要
今回作成したプログラムは、入力されたローマ字に対応する点字をテキストで出力します。
以下が実行例です。
tenji_maker = TenjiMaker.new
puts tenji_maker.to_tenji('A HI RU')
#=> o- o- oo
# -- o- -o
# -- oo --
puts tenji_maker.to_tenji('KI RI N')
#=> o- o- --
# o- oo -o
# -o -- oo
- 点字の点には半角小文字の
o
を、出力されない部分には半角ハイフン-
をつける - 点字と点字の間は上の実行例のように、半角スペースで区切る
- ローマ字から点字への変換は以下のサイトに従う
このお題の詳細はRead Meで詳しく書かれてあるので、ここまでにします。
それでは解説をしていきます。
##ロジックの解説
このお題を突破するには、大きく分けると以下の3つの処理が必要だと思いました。
番号 | 処理内容 |
---|---|
1 | 入力されたローマ字を読み取る処理 (どのローマ字が入力されたのか、何文字目なのか、何文字入力されたのか) |
2 | ローマ字を点字に変更する処理 |
3 | 点字を出力する処理 (どの点字を入力するのか、何文字目に変更した点字を出力するのか、何文字点字を出力するのか) |
そしてこれに準じて、作ったメソッドは3つあり、
1,3の入力されたローマ字の読み取り、出力を担当するread_and_output
2の主に母音の処理を担当する,judge_mother_text
2の母音以外のその他処理を担当するjudge_others_text
本出力を行うto_tenji
メソッドの中身は下記になります。
def to_tenji(text)
read_and_output(text)
end
全体のロジックを図解すると下記のような感じです。
ローマ字を読み取り、点字を出力するread_and_output
メソッドについて
まずこのメソッドの全体的な流れとしては下記コードでコメントアウトした箇所のような形です。
def read_and_output(text)
#1.入力された文字を取得
#2.その文字を自作メソッド(judge_mother_text, judge_others_text)を用いて、ローマ字から点字に変換
#3.ローマ字から点字に変換した字を返す
end
そして下記の「何文字入力されたのか」と「どんなローマ字が入力されたのか」の処理によって、
#1.入力された文字を取得
することができます。
# 1.入力された文字を取得
def read_and_output(text)
nil_number = text.count(' ') #半角の空白をカウント
text_number = nil_number + 1 #文字数を取得
text_array = text.split #入力された文字ごとに配列の要素として格納
(省略)...
end
例えば、「A HI RU」が入力されたときに
text_number = 3
text_array = ["A" "HI" "RU"]
という形になります。
なので、text_array
は配列として扱われ、入力された文字列を配列として扱うことができるようになりました。
この時点で、下記のように入力された文字を1字ずつ扱うことができます。
p text_array[0]
#"A"
次に入力されたローマ字を点字に変換する処理を行います。 そして、点字は下の画像(ちなみに「あ」)のように1文字が3行2列と決まっていて、 ![スクリーンショット 2021-12-13 4.46.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1584967/3c769ac6-8767-a50d-9ecf-75a3156e7f7a.png) 2文字以上になると,3行2列が空白を通して、連なっていきます。 ![スクリーンショット 2021-12-13 5.14.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1584967/829a4c4a-1100-692f-b655-ee4194dcfb5d.png) *引用 [全視情協:点字とは \- 点字のしくみ](http://www.naiiv.net/braille/?tenji-sikumi)*
上記の性質を利用して、点字用の変数配列@tenji_str1
,@tenji_str2
,@tenji_str3
を作成し、取得した文字数(text_number
) × --
( one_letter
)を代入しました。
例えば「A HI RU」が入力された場合、各配列型変数に入る値は下表のようになります。1文字3列分です。なのでこの場合だと、「A」が[0,1,2],「HI」が[3,4,5],「RU」が[6,7,8]
また、各文字の3列目には何も入ってないわけではなく、半角の空白が入っています。
| 点字1文字「あ」 | [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] | [8] |
|:---|:---:|:---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|@tenji_str1
|- |- | |- |- | |- |-| |
|@tenji_str2
|- |- | |- |- | | -|-| |
|@tenji_str3
|- |- | |- |- | | -|-| |
以上の処理が、下記になります。
#2.入力された文字を自作メソッド(judge_mother_text, judge_others_text)を用いて、ローマ字から点字に変換
def read_and_output(text)
...(省略)
one_letter = '-- '
@tenji_str1 = one_letter * text_number #点字1行目
@tenji_str2 = one_letter * text_number #点字2行目
@tenji_str3 = one_letter * text_number #点字3行目
(省略)...
end
次にeach_with_index
で、入力されたtext_array
に格納された配列型のローマ字を1字ずつループさせることで、ループ内で点字に変換していきます。
#2.入力された文字を自作メソッド(judge_mother_text, judge_others_text)を用いて、ローマ字から点字に変換
def read_and_output(text)
...(省略)
text_array.each_with_index do |text, num|
judge_mother_text(text, num * 3) #母音処理
judge_others_text(text, num * 3) #母音以外を処理
end
(省略)...
end
次にローマ字から変換した点字が代入された@tenji_str1
,@tenji_str2
,@tenji_str3
を1つの文字列string
としてread_and_output
の返り値とします。
#3.ローマ字から点字に変換した字を返す
def read_and_output(text)
...(省略)
string = @tenji_str1.rstrip + "\n" << @tenji_str2.rstrip + "\n" << @tenji_str3.rstrip
string
end
以上が入力されたローマ字を読み取り、点字を出力する処理を扱うread_and_output
メソッドのロジック解説でした。
母音のローマ字を点字に変更するjudge_mother_text
メソッドについて
ここからはどうやって母音のローマ字を点字に変換したのかというロジックを解説していきます。
前提として、以下のようにすでに-
が代入された状態の点字出力用の3つの変数が渡された状態で、処理を開始します。
点字1文字 | [i] | [i+1] | [i+2] |
---|---|---|---|
@tenji_str1 |
- (1番) | - (4番) | |
@tenji_str2 |
- (2番) | - (5番) | |
@tenji_str3 |
- (3番) | - (6番) |
結論から始めるとcase when
とinclude?
を用いて、各ローマ字の母音が含まれている場合、指定箇所にo
を入力する。といった処理です。
例をあげると、
def judge_mother_text(text,number)
i = number
case
when text.include?('A') #textにAが含まれている場合に下記処理を実行
@tenji_str1[i] = 'o' #1番にoを代入
...省略
end
end
Aが入力されたので、1番にo
を代入。といった形で母音が含まれている文字ごとにo
を指定位置に代入し、入力されたローマ字に準じて、点字に変換します。
母音以外のその他ローマ字を点字に変更するjudge_others_text
メソッドについて
ここからはどうやって母音以外のローマ字を点字に変換したのかというロジックを解説していきます。
前提として、点字の子音(母音以外)は母音(あ、い、う、え、お)との組み合わせでできます。
どういうことかというと点字の「あ,い,う」と「か,き,く」を見比べるとわかるのですが(下記画像参照)、か行は母音の点に6番の点を加えただけ。なので、
母音 + 6番 = か行
この調子でサ行もいっちゃいましょう。
母音 + 5番 + 6番 = さ行
引用 全視情協:点字とは - 点字のしくみ
ということで子音は母音との組み合わせでできていることを説明しました。
そして、この法則をうまく利用したのがjudge_others_text
メソッド
case
と正規表現を用いて、任意の字から始まっている2字のローマ字がある場合、指定箇所にo
を代入する。といった処理です。
例を上げると、「K」から始まる2字のローマ字には6番にo
を代入する。
もっと詳細に言えば「KA」が入力されている場合、judge_mother_text
で「A」を点字に変換後、judge_others_text
で「K」を点字に変換します。
以上のようなロジックで子音のローマ字を点字に変換する処理を行っていました。
def judge_others_text(text,number)
i = number
case text
when /K\D/ #Kから始まる2文字の場合、下記処理を実行
@tenji_str3[i+1] = 'o' #6番にoを代入
...省略
end
end
##コードのアピールポイント
頑張ったところ
- 変換された点字を出力するロジックの実装
点字の文字数がどれだけでも3行であるという特徴(このプログラム課題上では)を活かして、@tenji_str1
,@tenji_str2
,@tenji_str3
の3つの文字列型変数を作り、最後にまとめて1つの文字列string
にまとめて返したロジックは我ながらよく頑張って考え抜いた箇所です。
苦労したところ
- ローマ字を点字に変換するところ
「や行」,「わ」などの例外部分は特に母音の出力がデフォルトとは違うので、苦労しました。
工夫したところ
-
splitメソッドを用いて入力されたローマ字の文字列を分割し、配列として扱ったところ
-
正規表現を用いて子音(母音以外)の条件分岐をしたところ
##全体を通しての感想
まだ使ったことのないメソッドを使ったり、
点字について深く知ることができたり、
Qiitaの記事で自分の書いたコードをアウトプットしたり、
初めてのこと尽くしでしたが、なんとかやり切ることができ、ホッとしています。
エンジニア転職に向けて、Rubyの総復習をこのプログラム課題を通してできたので、大変勉強になりました!
伊藤さんにメッセージ
チェリー本にはいつも大変お世話になっております。
またQiitaの良質な記事にもいつも助けられています。
これからも勝手ですがお世話になります!