5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念-Advent Calendar 2021

Day 8

Rubyで点字メーカープログラム作成にチャレンジしました! 〜Qiita Advent Calendar 2021〜

Last updated at Posted at 2021-12-08

はてなBlog20211208.png

:cherries:この記事について

この記事は、伊藤 淳一(@jnchito)さんによるQiita Advent Calendar 2021「Rubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念-」の8日目(12/8)の記事です。

:cherries:自己紹介と参加した理由

はじめまして、paruと申します。今回Qiitaへの初投稿となります。
2021年4月よりフィヨルドブートキャンプというオンラインプログラミングスクールでRubyを初めとするプログラミングとwebエンジニアになるための知識と技術を学んでいます。
Rubyに出会い学び始めて8ヶ月が経ちました。
まだ超初心者ですが、毎日スクールの仲間たちとの輪読会で親しんでいるチェリー本とメンターの伊藤さんに、これまでの学びへの感謝の気持ちを表したいと思い、今回の企画への参加を思い切って申し込みました。

:cherries:プルリクエスト

※テストコードの追加はありません。

:cherries:点字について知る

点字についての知識を全く持っていなかったので、まずはじっくりと点字の構成、成り立ちについて学び、多くのひらがなは母音+子音の組み合わせで点字として表示ができるということを知りました。
スクリーンショット 2021-12-07 16.10.13.png
全視情協:点字とは - 点字のしくみより

今回のプログラムでは、変換する文字の対象は

  • あいうえお、かきくけこ、(省略)、やゆよ、らりるれろ、わ、ん
    と指定されてかなり易しくしていただけているのですが、上記の母音+子音で表現する原則とは違う表記をする文字があります。
    それが下記の5つ、「や、ゆ、よ、わ、ん」です。
    image.png

:cherries:プログラミングの進め方

上記のことを踏まえて、今回は文字列と配列を使いながらプログラミングを進めていくことにしました。

  • 点字の「●」になっている場所を下記のような数字(インデックス)で認識します。
- そして、母音と子音の組み合わせの原則で表現できる文字については、下記の図のように●になる数字をテーブルに定義することにします。 ![1_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1652831/da1298e7-fb28-7d33-cbb2-f0560bcbbb34.jpeg) - 特別対応が必要な5文字は別のテーブルで数字を定義しておきます。 ![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1652831/50fe529f-8532-aeee-c960-511dc55c0a92.jpeg)

こんな感じで、TenjiMakerクラスの一番上にテーブルを定義しました。
値の配列の数字が点字の「○」になる部分を表しています。

  NORMAL_LETTERS = {
    'A' => [0],
    'I' => [0, 2],
    'U' => [0, 1],
    'E' => [0, 1, 2],
    'O' => [1, 2],
    'K' => [5],
    'S' => [3, 5],
    'T' => [3, 4],
    'N' => [4],
    'H' => [4, 5],
    'M' => [3, 4, 5],
    'R' => [3]
  }.freeze

  SPECIAL_LETTERS = {
    'YA' => [1, 4],
    'YU' => [1, 4, 5],
    'YO' => [1, 3, 4],
    'WA' => [4],
    'NN' => [3, 4, 5]
  }.freeze

それでは、作成したプログラムのロジックを説明していきます。

:cherries:ロジックの解説

メインロジック

def to_tenji(text)
  text_array = text.split.map(&:chars)
  braille_array = convert(text_array).map do |element|
    @braille_letter = +'------'
    make_braille(element)
    @braille_letter.scan(/.{1,2}/)
  end
  braille_array.transpose.map { |two_degits| two_degits.join(' ') }.join("\n")
end

(1ステップずつ解説)

text_array = text.split.map(&:chars)

入力された文字列を1文字ずつ、そして母音と子音に分割して配列に入れます。
(例) 'A HI RU' → [["A"], ["H", "I"], ["R", "U"]]

braille_array = convert(text_array).map do |element|
  @braille_letter = +'------'
  make_braille(element)
  @braille_letter.scan(/.{1,2}/)
end
  • convertというprivateメソッドで上記のアルファベットの配列を数字情報に変換します。(メソッドの解説は次の項に書いています。)
    (例) [["A"], ["H", "I"], ["R", "U"]][[0], [4, 5, 0, 2], [3, 0, 1]]

  • できた配列から1要素ずつ取り出し、make_brailleというprivateメソッドで、基本となる文字列"------"の該当部分を'o'に変換します。(メソッドの解説は次の項に書いています。)
    (例) [4, 5, 0, 2]"o-o-oo"

  • その文字列を2文字ずつに分割して配列を作成して新しい配列を作ります。
    (例) "o-o-oo"["o-", "o-", "oo"]

    • ここでは文字列を分割後に配列を作りたいためscanメソッドを使用しました。正規表現は .scan(/.{1,2}/) を使いましたが、たった2文字なので .scan(/../)の方が簡単だったと後で気づきました。
  • 全入力文字の処理が終わるとこんな配列が出来上がっています。
    (例) [["o-", "--", "--"], ["o-", "o-", "oo"], ["oo", "-o", "--"]]

braille_array.transpose.map { |two_degits| two_degits.join(' ') }.join("\n")
  • 最後に、配列を行列と見なして行と列を入れ替えるtransposeメソッドを用いて、スペースと改行を付加して出力します。これで出来上がりです!!
(出力結果)
o- o- oo
-- o- -o
-- oo --

privateメソッド2つ

convertメソッド

def convert(text_array)
  text_array.map do |first, second|
    second ||= first
    SPECIAL_LETTERS[first + second] || (NORMAL_LETTERS[first] | NORMAL_LETTERS[second])
  end
end

このメソッドではアルファベットの配列をテーブルを参照して数字情報に変換します。  
(例) [["A"], ["H", "I"], ["R", "U"]][[0], [4, 5, 0, 2], [3, 0, 1]]

まずは子音firstと母音secondに引数の配列の1要素を代入します。

(Nilガード)

もしも母音のみまたは"N"の場合はsecondがnilになるので、 ||=のnilガードでfirstの文字をsecondに入れておきます。

(短絡評価と配列の和集合)

そして、まずはSPECIAL_LETTERSのテーブルで[first + second] をキーにして特別な5文字を探し、当てはまったらその値を返します。
SPECIAL_LETTERSで見つからなかったら、NORMAL_LETTERSテーブルから子音と母音をキーに値を取得し、配列の和集合|で1つの配列にします。

make_brailleメソッド

def make_braille(element)
  element.each do |number|
    @braille_letter[number] = 'o'
  end
end

このメソッドでは基本となる文字列"------"に対して、数字で指定された部分を'o'に変換します。
(例) [4, 5, 0, 2] → "------"の4,5,0,2番目を変換 → "o-o-oo"

おまけ

if __FILE__ == $PROGRAM_NAME
  text = ARGV[0]
  puts TenjiMaker.new.to_tenji(text)
end

要件には指定されていませんでしたが、コマンドから入力されたローマ字を点字への変換ができるように直接このファイルを実行できるコードを加えました。

[実行例]
 ruby lib/tenji_maker.rb 'A HI RU'
o- o- oo
-- o- -o
-- oo --

:cherries:点字メーカープログラムを作成した感想

チェリー本をあちこち読み返しながら楽しく作成することができました。
今まで全く馴染みのなかった点字の仕組みを知ることができたことも大きな収穫です。
とても良い経験をさせていただきありがとうございました!
点字にとても興味が湧いたので、皆さんが作られたプログラムをじっくりと読ませていただきながら、今後全文字対応できるプログラムを自由研究で書いてみたいなと思っています。

:cherries:伊藤さんにメッセージ

チェリー本改訂第2版の出版おめでとうございます!
今後の一番の愛読書になること間違いなし!です〜:blush:

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?