ファイル入出力の処理例

ファイル入出力の応用例として、決められた商品に対する、 支払金額計算プログラムを作ろう。以下のような仕様のプログラムを作りたい。

  1. 商品名と単価を書いたファイルをデータファイルとして読み込む。
  2. 商品一覧をユーザに提示する。
  3. ユーザに商品番号を入力させる。
  4. 商品番号入力が終了したら合計金額を計算し、出力する。

実際にプログラムを動かすときのシミュレーションをしてみると プログラムの設計方針を立てやすいだろう。

プログラムの動作イメージ

以下のように、商品と価格の書かれたファイルがあったとする。

price.txt

サーモン        110円
イカゲソ        110円
えんがわ        110円
マグロ          110円
ネギトロ        110円
蛸              110円
赤貝            110円
穴子            110円
鉄火巻          110円
カッパ巻        110円
ハマチ          110円
サヨリ          180円
中トロ          180円
牛トロ          180円
寒ブリ          180円
イクラ          240円
タラバ          240円
大トロ          360円
ウニ            360円

プログラムを起動すると、このファイルを自動的に読み込み、その内容を メニュー番号とともに標準出力に出す。

  0 サーモン        110円
  1 イカゲソ        110円
  2 えんがわ        110円
  3 マグロ          110円
  4 ネギトロ        110円
  5 蛸              110円
  6 赤貝            110円
  7 穴子            110円
  8 鉄火巻          110円
  9 カッパ巻        110円
 10 ハマチ          110円
 11 サヨリ          180円
 12 中トロ          180円
 13 牛トロ          180円
 14 寒ブリ          180円
 15 イクラ          240円
 16 タラバ          240円
 17 大トロ          360円
 18 ウニ            360円

ユーザがメニュー番号を順次入力し終えるとそれまで入力したメ ニューの価格を全て足した金額を出力する。

全部で2490円でございます。

会計プログラムの設計

上記の動作イメージから分かることは、プログラムのおおまかな流れとして

  1. 価格データファイル(price.txt)を読み、品目と金額 を全て記憶する。
  2. 一覧を提示してユーザからの注文入力を繰り返す。
  3. 合計金額を出力する。

の3つがある。最後に合計金額を出力するので 2.のところで、 つねに金額を足していなければならない。これらのことに注意して 各段階の手順をプログラムにしていこう。

  1. 価格データファイルの読み込み

    まず、price.txtデータファイルから価格リストを読み 込み商品名を配列変数に入れる部分を作ろう。さらにその値段部分を別の 配列変数に入れておこう。ここでは商品名を入れる配列を menu変数、価格を入れる配列をprice 変数としよう。するとプログラムの該当部分は 以下のようになる。

    menu = []
    price = []
    
    i = 0
    open("price.txt", "r") do |neta| # price.txtを読み込みモードで開く
      while line = neta.gets	 # ファイルから1行ずつ読む
        if /(\S+)\s+(\d+)円/ =~ line # (数字)円 というパターンがあれば
          menu  << $1		 # $1 は商品名
          price << $2.to_i	 # $2 が「数字」に当てはまるので整数化
          printf("%3d %s", i, line)  # 商品番号と、読み込んだ行を出力
          i += 1
        end
      end
    end
    

    商品データの読み込みが完了したときの i の値は、「最後の商品番号+1」が入っていることを踏まえて 以下に進もう。

  2. 注文の読み込み

    続いてユーザが対話入力で、商品番号を入れるループを作ろう。 注文が終わったら "q" を入力する約束にしてループを作成する。

    while true
      print "御注文は(番号で入れてね、q で終了)?: "
      line=gets.chomp!		# ユーザの入力を line に入れる
      if line == "q"		# "q" を入力したら
        break			#    終了
      end
      number = line.to_i		# 整数(メニュー番号)にする
      if number < 0 || number >= menu.length
        puts "そんなメニューねぇでガス"
        redo
      end
      printf("はあーい、「%s」一丁\n", menu[number])
      sum += price[number]
    end
    
  3. 結果(精算金額)出力

    変数 sum に入っている合計金額を出力して終了する。

    print "おあいそでガス\n"
    printf("全部で %d 円でガス。まいどっ\n", sum)
    

以上を組み合わせることでプログラムが完成する。

sushi.rb

#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-

sum = 0
menu = []
price = []

i = 0
open("price.txt", "r") do |neta|	# price.txtを読み込みモードで開く
  while line = neta.gets		# ファイルから1行ずつ読む
    if /(\S+)\s+(\d+)円/ =~ line		# (数字)円 というパターンがあれば
      menu  << $1			# $1 は商品名
      price << $2.to_i			# $2 が「数字」に当てはまるので整数化
      printf("%3d %s", i, line)		# 商品番号と、読み込んだ行を出力
      i += 1
    end
  end
end

while true
  print "御注文は(番号で入れてね、q で終了)?: "
  line=gets.chomp!		# ユーザの入力を line に入れる
  if line == "q"		# "q" を入力したら
    break			#    終了
  end
  number = line.to_i		# 整数(メニュー番号)にする
  if number < 0 || number >= menu.length
    puts "そんなメニューねぇでガス"
    redo
  end
  printf("はあーい、「%s」一丁\n", menu[number])
  sum += price[number]
end

print "おあいそでガス\n"
printf("全部で %d 円でガス。まいどっ\n", sum)

実行

sushi.rbprice.txtを保存し、実際に実行してみ よう。

./sushi.rb