7日目のゴールとテーマ
7日目のテーマは「名簿アプリを“ちょっと賢く”する:検索と並べ替え、そして入力ミスへの対応」です。
6日目までで、Person クラス+配列+メニューで、かなりアプリらしい形になりました。
今日はそこから一歩進めて、
名前で検索できるようにする
年齢順に並べ替えて表示できるようにする
メニュー入力などで“変な入力”が来ても落ちないようにする
という、「実際に使うときに欲しくなる機能」と「エラーに強い書き方」を体験していきます。
いまの名簿アプリをざっくり振り返る
6日目までの構造を言葉で整理する
すでにあなたのアプリは、こんな構造になっています。
Person クラス
名前・年齢・趣味を持ち、introduction で自己紹介文を返す。
build_person_from_input
ユーザーから入力を受け取り、Person を1人分作って返す。
people(配列)
Person オブジェクトを複数まとめて持つ「名簿」。
メニュー+メインループ
「全員表示」「追加」「20歳未満だけ表示」「終了」を選べる。
今日はここに「検索」「並べ替え」「入力チェック」を足していきます。
名前で検索する機能を考える
まずは“やりたいこと”を日本語で書いてみる
名前検索の仕様を、いったん日本語で整理します。
ユーザーに「探したい名前(または一部)」を入力してもらう
名簿の中から、その文字列を含む人を探す
見つかった人たちの自己紹介を表示する
1人も見つからなければ、その旨を表示する
これを Ruby に翻訳していきます。
部分一致検索のイメージ
「完全一致」ではなく「部分一致」にすると、使い勝手がよくなります。
「た」で検索したら「たろう」「たかし」「やまだ」などがヒットする
「田」で検索したら「田中」「山田」がヒットする
Ruby では、文字列に対して include? を使うと「含まれているか」を判定できます。
"たろう".include?("た") # true
"たろう".include?("ろう") # true
"たろう".include?("はな") # false
Rubyこれを Person の name に対して使えば、「名前にその文字列が含まれている人」を探せます。
名前検索の処理をメソッドとして書く
メニュー項目を1つ増やすイメージ
メニューに「4: 名前で検索」を追加するとします。
def show_menu
puts "========================"
puts "名簿アプリ メニュー"
puts "1: 全員の自己紹介を表示"
puts "2: 新しい人を追加"
puts "3: 20歳未満の人だけ表示"
puts "4: 名前で検索して表示"
puts "0: 終了"
puts "番号を入力してください:"
end
Rubyメインループ側も、4 を受け取ったときの処理を足します。
elsif choice == 4
handle_search_by_name(people)
Rubyでは、この handle_search_by_name を書いていきます。
handle_search_by_nameの中身
def handle_search_by_name(people)
if people.empty?
puts "まだ登録されている人がいません。"
return
end
puts "検索したい名前、またはその一部を入力してください:"
keyword = gets.chomp
if keyword.strip == ""
puts "空のキーワードでは検索できません。"
return
end
matched = people.select do |person|
person.name.include?(keyword)
end
if matched.empty?
puts "「#{keyword}」を含む名前の人は見つかりませんでした。"
return
end
puts "「#{keyword}」を含む名前の人が#{matched.length}人見つかりました。"
matched.each_with_index do |person, idx|
puts "------------------------"
puts "#{idx + 1}人目:"
puts person.introduction
end
end
Rubyここでの重要ポイントを深掘りします。
people が空なら、検索しても意味がないので早めに return している
keyword が空文字(スペースだけなど)のときも、検索せずに戻っているselect で「名前に keyword を含む人だけ」を集めている
1人も見つからなければ、その旨を表示して return
見つかった人たちの自己紹介を順番に表示
特に person.name.include?(keyword) の部分が「部分一致検索」の核心です。
年齢順に並べ替えて表示する
並べ替えのイメージをつかむ
次は「年齢順に並べて表示したい」という欲張りを叶えます。
やりたいことはこうです。
名簿の人たちを、年齢の小さい順(若い順)に並べ替える
その順番で自己紹介を表示する
Ruby では、配列に対して sort_by を使うと「ある基準で並べ替え」ができます。
numbers = [5, 2, 9, 1]
sorted = numbers.sort # [1, 2, 5, 9]
RubyPerson の配列の場合は、「年齢」を基準に並べ替えたいので、
sorted_people = people.sort_by { |person| person.age }
Rubyと書きます。
これで、「age が小さい順」に並んだ新しい配列ができます。
メニューに「年齢順表示」を追加する
メニューにもう1項目足します。
puts "5: 年齢の若い順に全員を表示"
Rubyメインループ側も対応します。
elsif choice == 5
handle_show_sorted_by_age(people)
Rubyhandle_show_sorted_by_ageの中身
def handle_show_sorted_by_age(people)
if people.empty?
puts "まだ登録されている人がいません。"
return
end
sorted = people.sort_by { |person| person.age }
puts "年齢の若い順に自己紹介を表示します。"
sorted.each_with_index do |person, idx|
puts "------------------------"
puts "#{idx + 1}人目(#{person.age}歳):"
puts person.introduction
end
end
Rubyここでの重要ポイントは、
people.sort_by { |person| person.age } で「年齢を基準に並べ替え」している
元の people はそのまま、新しい配列 sorted に結果が入る
表示するときに「何歳か」も一緒に出してあげると分かりやすい
ということです。
sort_by は、Ruby で「オブジェクトの配列を並べ替える」ときの定番です。
「何を基準に並べたいか」を { |person| person.age } の部分で指定します。
入力ミスに強いメニューにする
いまの read_menu_number の弱点
6日目では、メニューの番号をこう読んでいました。
def read_menu_number
input = gets.chomp
input.to_i
end
Rubyto_i は、数字以外が混ざっていても 0 にしてしまいます。
“abc” → 0
“1abc” → 1
つまり、ユーザーが「abc」と打っても、
「0が入力された」とみなされて終了してしまう可能性があります。
これだと、ちょっと不親切です。
ちゃんと「数字かどうか」をチェックする
ここで、少しだけ“丁寧な”読み方に変えます。
def read_menu_number
loop do
input = gets
return 0 if input.nil? # Ctrl+D などで入力が終わった場合の保険
text = input.chomp
if text.match?(/\A[0-9]+\z/)
return text.to_i
else
puts "数字で入力してください。もう一度どうぞ:"
end
end
end
Rubyここでの重要ポイントを深掘りします。
gets が nil を返すことがある(入力ストリームが終わったとき)ので、その場合は 0 を返して終了扱いにしているtext.match?(/\A[0-9]+\z/) は「0〜9の数字だけで構成されているか」をチェックしている
数字だけなら to_i して返す
そうでなければ「数字で入力してください」とメッセージを出して、loop の先頭に戻る
これで、ユーザーが「abc」や「1a」などと入力しても、
アプリが勝手に終了したり、変なメニューに飛んだりしなくなります。
正直、ここは少し“プログラミングっぽい”書き方になりますが、
「入力をちゃんとチェックする」という感覚は、どの言語でも超重要です。
名前入力にも“空文字チェック”を入れてみる
「名前が空の人」を作らないようにする
今の build_person_from_input は、名前が空でもそのまま Person を作ってしまいます。
それを少しだけ丁寧にします。
def read_non_empty_line(message)
loop do
puts message
input = gets
return "" if input.nil?
text = input.chomp
if text.strip == ""
puts "空では登録できません。何か入力してください。"
else
return text
end
end
end
Rubyこのメソッドは、
メッセージを表示する
入力を受け取る
空文字やスペースだけなら、もう一度聞き直す
何か文字が入っていれば、それを返す
という「空でない1行」を読むための部品です。
これを使って、build_person_from_input を書き換えます。
def build_person_from_input
name = read_non_empty_line("名前を入力してください:")
puts "年齢を入力してください:"
age_text = gets.chomp
age = age_text.to_i
hobby = read_non_empty_line("好きなこと(趣味)を入力してください:")
Person.new(name, age, hobby)
end
Rubyこれで、「名前が空の人」「趣味が空の人」は作られなくなります。
こういう小さな“優しさ”が、アプリの使い心地を大きく変えます。
7日目まででできることを俯瞰してみる
あなたの名簿アプリはここまで来ている
7日目の時点で、あなたの Ruby アプリはすでにこんなことができます。
Person クラスで「人」を表現している
Person の配列を「名簿」として扱っている
メニューから操作を選べる
新しい人を追加できる
全員分の自己紹介を表示できる
20歳未満だけを絞り込んで表示できる
名前で検索して表示できる(部分一致)
年齢の若い順に並べ替えて表示できる
メニュー番号の入力ミスにある程度耐えられる
名前や趣味が空のまま登録されるのを防いでいる
これはもう、「学習用のサンプル」を超えて、
小さな“実用アプリ”の入り口に立っています。
7日目のまとめ
今日のキーワードを整理します。
include?
文字列に対して「この文字列を含んでいるか?」を調べるメソッド。person.name.include?(keyword) で部分一致検索ができる。
select
配列から「条件に合う要素だけ」を集めて新しい配列を作る。
検索結果やフィルタリングに使える。
sort_by
配列を「ある基準」に従って並べ替える。people.sort_by { |p| p.age } で年齢順に並べ替え。
入力チェック
メニュー番号が数字かどうかを正規表現でチェックする。
空文字を弾く read_non_empty_line のような“入力専用メソッド”を作ると、
アプリ全体の入力が安定する。
「ちょっと賢いアプリ」にする視点
検索・並べ替え・入力ミスへの対応は、
どんなアプリでもほぼ必ず出てくる要素。
ここを自分の手で書けたのはかなり大きいです。

