(10)06/22の授業内容

  1. openメソッド
  2. 前回のプログラムは,ファイルから1行ずつ読み込み特定の処理をおこなうものでした.ファイルの指定は,プログラムを実行する際に具体的にscore.txt入力することで行われていました.しかし,常に同じファイルを読み込むのであればこのような指定は面倒です.また場合によってはデータを読み込むのではなく,データを書き出すということもありえます.このような場合に利用するのがopenメソッドです.様々な使い方がありますが,以下の方法を把握しておけばよいでしょう

    open("ファイル","モード")do |変数|
        ファイルを読み込んで行う処理
    end

    ファイル:開きたいファイル名を指定します.ファイルがプログラムと同一ディレクトリにある場合は,単にファイル名を指定するだけでよいですが,異なるディレクトリにある場合には../data.txtのようにパス指定をする必要があります

    モード:開いたファイルを読み込みたいのか,書き込みたいのか,新規作成したいのかなどの用途によりモードは異なります.6種類あります

    r:読み込み専用

    r+:読み込み/書き込用

    w:書き込み専用.当該ファイルが存在しない場合には新規作成し,存在する場合はそのデータを全て削除して新しくファイルを作成する

    w+:読み込み/書き込み用で,その他はwと同じ

    a:追加書き込み専用.当該ファイルが存在しない場合は新規作成するが,存在する場合はデータの末尾に続けて書き込みを行う

    a+:読み込み/追加書き込み用で,その他はaと同じ

    変数:開いたファイルからの読み込みや,開いたファイルへの書き込みを行う際に使うもので,任意の名前でよい

  3. openメソッドを使ったファイルへの書き込み
  4. ファーストフードのPOSを想定したプログラムを作ります.POSは会計を行うのみでなく,在庫管理や販売戦略の分析にも利用できるものです.ここでは,お会計の際に客層を入力することで,客層別の人数と客単価を表示できるプログラムを作っています.下記はデータ入力用のプログラムで,お会計を行うことで,客層と,ハンバーガー,ドリンク,アップルパイの購入金額をpos_data.outという名前のファイルに書き込みます.pos_input.rbという名前をつけて保存し,実行してみましょう.

    実行したらktermでcat pos_data.out[Retern]と入力すると,書き込まれたデータを見ることができます(ちなみにpos_data.outを削除するときのコマンドはrmで,rm pos_data.out[Return]と入力します)

    #!/usr/koeki/bin/ruby
    
    burger = 0  #ハンバーガーの金額
    drink = 0  #ドリンクの金額
    pie = 0  #アップルパイの金額
    i = 0  #配列に代入する際のインデックス
    sum = 0  #合計金額
    
    open ("pos_data.out", "a") do |pos|
      while true
        STDERR.print "客層の選択(1:学生、2:会社員、3:ファミリー、9:営業終了):"
        customer = gets.chomp!.to_i
          if customer == 9
            then STDERR.print "本日の営業は終了しました\n"
            break
          end
        STDERR.print "ハンバーガーはいかがでしょうか(金額を入力):"
        burger = STDIN.gets.chomp!.to_i
        STDERR.print "お飲み物はいかがでしょうか(金額を入力):"
        drink = STDIN.gets.chomp!.to_i
        STDERR.print "ただいまアップルパイが100円になっております(y or n):"
        a = STDIN.gets.chomp!
          if a == "y"
            pie = 100
          else
            pie = 0
          end
        sum = burger + drink + pie
        STDERR.printf "お会計%d円になります。どうもありがとうございました\n", sum
        pos.printf "%d \t %d \t %d \t %d\n", customer, burger, drink, pie
        i += 1
        STDERR.print "\n"
        STDERR.print "お次のお客様どうぞ\n"
      end
    end
    

    新しく出てきた部分について説明します

    open ("pos_data.out", "a") do |pos|

    pos_data.outというファイルを開きます.モードは"a"なので追加書き込み専用です.一番最初に実行した場合は,pos_data.outは存在しないので新規作成されますが,何度か繰り返し実行すると既存のpos_data.outの末尾に実行結果が追加で書き込まれます.なおposはpos_data.outに書き込みを行う際の変数として指定しています

    pos.printf "%d \t %d \t %d \t %d\n", customer, burger, drink, pie

    通常のprintfにpos.がついています.posは書き込みを行う際の変数として指定されたものです.pos.printfとすることでディスプレイではなく,ファイルに対して表示(=書き込み)が行われます.実行をしてもディスプレイに何も表示されないのはprintfではなくpos.printfとなっているためです.なお""内の\tはタブの意味でスペースを空けるという意味です.キーボードのTabキーと同じ働きです

    STDIN(標準入力)とSTDERR(標準エラー出力)

    ファイルを指定した場合,getsメソッドはキーボードからの読み込みと,ファイルからの読み込みが可能になります.またprintやprintfメソッドはディスプレイへの表示,ファイルへの書き込みが可能になります.このためこれらのメソッドを使用する際にはどこから読み込むのか,どこへ出力するのかを指定しないと,思ったような結果にならないことがあります

    ファイルからの読み込み,ファイルへの書き込みを行う場合にはpos.gets, pos.print, pos.printfのようにファイルをopenしたときに指定した任意の変数をつけます.一方ディスプレイへの表示の場合はSTDERR.print,STDERR.printf,キーボードからの入力はSTDIN.getsをつける必要があります.

  5. openメソッドを使ったファイルからの読み込み
  6. 次は,書き込まれたpos_data.outを読み込んで,客層別の人数と客単価を表示するプログラムです.pos_analysis.rbと名前をつけて保存し,実行してみよう

    #!/usr/koeki/bin/ruby
    
    student_sum = 0  #学生の購入金額
    worker_sum = 0  #会社員の購入金額
    family_sum = 0  #ファミリーの購入金額
    student_count = 0  #学生の人数
    worker_count = 0  #会社員の人数
    family_count = 0  #ファミリーの組数
    
    open ("pos_data.out", "r") do |pos|
      while line = pos.gets
        if /(\w)\s+(\w+)\s+(\w+)\s+(\w+)/ =~ line
          if $1.to_i == 1  #客層が「学生」の場合
            student_sum += $2.to_i + $3.to_i + $4.to_i
            student_count += 1
          elsif $1.to_i == 2  #客層が「会社員」の場合
            worker_sum += $2.to_i + $3.to_i + $4.to_i
            worker_count += 1
          else  #客層が「ファミリー」の場合
            family_sum += $2.to_i + $3.to_i + $4.to_i
            family_count += 1
          end
        end
      end
    end
    
    print "\n"
    printf "学  生は%2d人,売り上げ合計は%6d円,客単価は%5d円です\n", student_count, student_sum, student_sum/student_count
    printf "会社員は%2d人,売り上げ合計は%6d円,客単価は%5d円です\n", worker_count, worker_sum, worker_sum/worker_count
    printf "家  族は%2d組,売り上げ合計は%6d円,客単価は%5d円です\n", family_count, family_sum, family_sum/family_count
    

    新しく出てきた部分について説明します

    open ("pos_data.out", "r") do |pos|

    今度はモードrで開いています.rは読み込み専用の意味です

    while line = pos.gets

    pos.getsとすることでpos_data.outから1行ずつ読み込みlineに代入します

    なおpos_input.rbとpos_analysis.rbは合体して1つのプログラムとすることもできます(pos_analysis.rbの先頭の#!usr/...の部分のみ消去).つまり,1つのプログラムの中でファイルを何度も閉じたり開いたりすることができます.実際に合体し,pos.rbという名前をつけて保存し実行してみよう

課題

以下の3つから1つを選んで実施する.1は8点満点,2は9点満点,3は10点満点で採点する

  1. pos.rbを改良する.下記のリストのうち1つ選んで実施する
  2. pos.rbを改良する.下記のリストのうち3つ選んで実施する
  3. リスト

    1. 客層を「学生」「会社員」「ファミリー」から「高校生」「大学生」「会社員」「ファミリー」に変更する(pos_input.rb部の最初の方や,pos_analysis.rb部のif部,printf部の修正が必要)
    2. 最後のprintf部で,人数,売上合計,客単価を表示するのではなく,人数,売り上げ合計,ハンバーガーの平均売上額,飲み物の平均売上額,アップルパイの平均売上額,客単価を表示するように変更する(pos_analysis.rb部のif部,printf部を修正する.客層別にハンバーガー,飲み物,アップルパイの売上合計を求め,人数で割って平均値を算出する)
    3. ハンバーガーや飲み物の注文を受ける際,金額を入力するのではなく,1.ハンバーガー,2.コロッケバーガー,3.スーパーウルトラグレートバーガーのように選択肢から選べるように変更する(変更方法はアップルパイを参考にすればよい)
    4. ハンバーガー,飲み物,アップルパイの3つのカテゴリを,例えば,ハンバーガー,飲みもの,アップルパイ,ポテトのように4つ以上のカテゴリにする(いろいろと細かい変更が必要)
  4. pos.rbを改良する.上記のリストのうちの3を実施したうえで,下記の変更も行う.それ以外にも自由に変更を加えてよい
  5. 「さっきハンバーガーと言ったけれど,やっぱりコロッケバーガー」というような注文に対して対応できるようにする.具体的には「以上でよろしいでしょうか」というメッセージを出し,よろしくない場合に注文を取り直す(入力した金額を修正する)ことができるようにする(この際,ハンバーガー,飲み物,アップルパイ全てを最初から入力しなおすように修正しても良いし,一部だけ修正できるように変更しても良い.やり方は様々なのでヒントはなし)


作成したプログラム,実行結果をメールでnaoya@e.koeki-u.ac.jp宛に送る.

課題の提出期限は6月25日(土)17:00まで


メール送信時の注意

Tips

emacsについて

Mewについて