Rubyプログラミング基礎講座
練習問題解答例

練習問題 2

  1. hw.rb

    #!/usr/local/bin/ruby
    print "世界のみなさんこんにちは!\n"
    print "世界のみなさんこんにちは!\n"
    print "世界のみなさんこんにちは!\n"
    

    print "〜〜\n" のかわりに puts "〜〜"でも良い。

  2. 修正後のgatagata.rb

    #!/usr/local/bin/ruby
    
    x = gets.chomp.to_i
    if x > 0
      printf("%d は正の数ね\n", x)
    end
    

    Emacsで編集している場合は、全ての行で[TAB] (またはC-i)をタイプして揃える。

練習問題 3

    1. 8

    2. 8

    3. 20

    4. "999"

    1. 0回。ifの比較で 5 > 5となり 不成立となるため。

    2. 5回。xの値が 5, 4, 3, 2, 1 のときに 内部を実行する。一般的にN回繰り返したい場合は

      x=N
      while x>0
       :
      end
      

      または、

      x=0
      while x<N
       :
      end
      

      とループ形成する。これらのやり方はwhile構文のある 他の言語でも同じ。Rubyの場合はさらに、

      N.times do |i|
       :
      end
      

      や、

      for i in 1..N
       :
      end
      

      などの便利な構文が豊富にある。

    3. 50回。0〜99の範囲の偶数の個数だけ実行する。
    1. if y%400 == 0 then
        puts "閏年"
      end
      
    2. if y%4 != 0 then
        puts "閏年でない"
      end
      
    3. if y%4 == 0 && y%100 != 0 then
        puts "閏年"
      end
      
    4. if y%4 != 0 || y%100 == 0 && y%400 != 0 then
        puts "閏年でない"
      end
      

練習問題 4

  1. gomasuri.rb

    #!/usr/local/bin/ruby
    n = gets.to_i
    i=0
    while i < n
      puts "きみは天才!"
      i += 1
    end
    
  2. homegoroshi.rb

    #!/usr/local/bin/ruby
    while true
      puts "きみは天才!"
    end
    
  3. rectangle.rb

    #!/usr/local/bin/ruby
    STDERR.print "長方形の面積を求めます。\n"
    STDERR.print "底辺は?(cm): "
    width = gets.to_i
    STDERR.print "高さは?(cm): "
    height = gets.to_i
    printf("面積は%d平方cmです\n", width*height)
    

    STDERR.はなくても本質的間違いではない。 以下のプログラムも同様。

  4. jetcoaster.rb

    #!/usr/local/bin/ruby
    STDERR.print "恐れ入りますが身長をcmで入力してください: "
    tall = gets.to_i
    if tall >= 120 && tall <= 180 then
      print "搭乗できます\n"
    else
      print "申し訳ありませんが搭乗できません\n"
    end
    

    この問題の場合は、比較で利用している不等号に= はあってもなくても構わない。

  5. kingin.rb

    #!/usr/local/bin/ruby
    STDERR.print "現在の年齢は?: "
    age = gets.to_i
    STDERR.print "今年の西暦は?: "
    year = gets.to_i
    while age < 100
      age += 1
      year += 1
      printf("%d年であなたは%d歳です。\n", year, age)
    end
    
  6. shopping.rb

    #!/usr/local/bin/ruby
    total = 0
    while true
      STDERR.print "商品名は?: "
      item = gets.chomp
      if item == "q" then
        break
      end
      STDERR.print "おいくら?: "
      price = gets.to_i
      printf("%-14s %5d円\n", item, price)
      total += price
    end
    print "お買い上げありがとうございました。\n"
    printf("合計は%6d円です。\n", total)
    

練習問題 5

    1. /./ → 1, 2, 3, 4
    2. /e./ → 1, 2, 3, 4

      .は「任意の1字」なのでeの文字の後に 何か文字があればその行は全てマッチする。

    3. /the/ → 3

      1行目のTheはTが違うのでマッチしない。

    4. /the/i → 1, 3

      大文字でもよくなるので今度は1行目のTheもマッチする。

    5. /[A-Z]/ → 1, 2, 4

      大文字のある行全てにマッチする。

    6. /^[A-Z]/ → 1

      行頭が大文字の行にマッチする。

    7. /[^A-Z]/ → 1, 2, 3, 4

      大文字以外のものは全ての行にある。

    8. /[a-z][A-Z]/ → 2

      小文字のあとに大文字が来るのは2行目の OggVorbis のみ。

    9. /\d/ → 1, 2
    10. /\d*/ → 1, 2, 3, 4

      *ならば直前の\dが0回でも 構わない。よって全てにマッチする。

    11. /\d+/ → 1, 2

      数字が1つ以上あれば良い。

    12. /\d*[A-Z]/ → 1, 2, 4

      \d* は数字がなくても良いのだから大文字のある 行全てにマッチする。

    13. /\d.*[A-Z]/ → 1, 2

      数字の見つかった場所より後に大文字があれば良い。

    14. /(.)\1/ → 2, 4

      同じ文字が繰り返し現れるのは2行目のOggVorbis(のg)と 4行目のbuffer(のf)。

  1. 実際に実行してみよ。

練習問題 6

  1. pts-sum.rb

    #!/usr/local/bin/ruby
    
    pts = [198, 37, 66, 28, 33, 45, 46, 32, 2, 99]
    sum=0
    for x in pts
      sum += x
    end
    printf("%d\n", sum)
    
  2. pts-avg.rb

    #!/usr/local/bin/ruby
    
    pts = [198, 37, 66, 28, 33, 45, 46, 32, 2, 99]
    sum=0
    for x in pts
      sum += x
    end
    printf("%f\n", sum.to_f/pts.length)
    

    整数だけなのでそのまま計算すると割り算も整数化される。 to_f で浮動小数点数に変換してから割り算する。

  3. pts-minmax.rb

    #!/usr/local/bin/ruby
    
    pts = [198, 37, 66, 28, 33, 45, 46, 32, 2, 99]
    sum=0
    min = max = pts[0]
    for x in pts
      sum += x
      if min > x then
        min = x
      elsif max < x then
        max = x
      end
    end
    printf("平均値 %f\n", sum.to_f/pts.length)
    printf("最大値 %d\n", max)
    printf("最小値 %d\n", min)
    
  4. tac.rb

    #!/usr/local/bin/ruby
    buffer = []
    n=0
    while str = gets
      buffer[n] = str
      n += 1
    end
    for l in buffer.reverse
      print l
    end
    

    もっとも短く書くと

    #!/usr/local/bin/ruby
    print readlines.reverse
    

    となる。

  5. register.rb

    #!/usr/local/bin/ruby
    name = []			# 商品名を配列にいれる
    value = []			# 価格を配列にいれる
    total = 0			# 価格の合計
    nitem = 0			# 読み取った商品の数
    while true
      STDERR.print "商品名は?: "
      item = gets
      if item == nil then		# 入力終わりなら gets はnilを返す
        break
      end
      name[nitem] = item.chomp!
      STDERR.print "おいくら?: "
      price = gets.to_i
      value[nitem] = price
      total += price
      nitem += 1
    end
    
    i=0
    puts ""				# 改行するだけ
    print "お買い上げありがとうございました。\n"
    while i < nitem 
      printf("%-14s %5d円\n", name[i], value[i])
      i += 1
    end
    puts "----------------------------"
    printf("%-13s %6d円です。\n", "合計は", total)
    

練習問題 7

  1. fcat.rb

    #!/usr/local/bin/ruby
    STDERR.print "見たいファイルは?: "
    fn = gets.chomp
    open(fn, "r") do |f|
      while fline=f.gets
        print fline
      end
    end
    
  2. fcat2.rb

    #!/usr/local/bin/ruby
    STDERR.print "見たいファイルは?: "
    fn = gets.chomp
    if test(?r, fn) then
      open(fn, "r") do |f|
        while fline=f.gets
          print fline
        end
      end
    else
      STDERR.print "そんなファイル読めないよ\n"
    end
      
    
  3. fcat3.rb

    #!/usr/local/bin/ruby
    STDERR.print "見たいファイルは?: "
    fn = gets.chomp
    begin
      open(fn, "r") do |f|
        while fline=f.gets
          print fline
        end
      end
    rescue
      STDERR.print "そんなファイル読めないよ\n"
    end
    
  4. sushikuine.rb

    #!/usr/local/bin/ruby
    
    sum = 0
    menu = []
    price = []
    i = 0
    
    open("price.txt", "r") do |neta| # price.txtを読み込みモードで開く
      while line = neta.gets	 # ファイルから1行ずつ読む
        if /(\w+)\s+(\d+)円/e =~ line # (数字)円 というパターンがあれば
          menu[i]  = $1		 # $1 は商品名
          price[i] = $2.to_i	 # $2 が「数字」に当てはまるので整数化
        end
        i += 1
      end
    end
    
    while true
      j=0
      while j<i
        # 商品番号と、ネタ名、価格を出力
        printf("%3d %s - %d\n", j, menu[j], price[j])
        j+=1
      end
    
      print "御注文は(番号で入れてね、q で終了)?: "
      line=gets.chomp!		# ユーザの入力を line に入れる
      if line == "q"		# "q" を入力したら
        break			#    終了
      end
      number = line.to_i		# 整数(メニュー番号)にする
      if number < 0 || number >= i
        puts "そんなメニューねぇでガス"
        redo
      end
      printf("はぁ〜い、「%s」一丁\n", menu[number])
      sum += price[number]
    end
    
    print "おあいそでガス\n"
    printf("全部で %d 円でガス。まいどっ\n", sum)
    
  5. parking.rb

    #!/usr/local/bin/ruby
    
    begin
      open("parking.tmpl", "r") do |pr|
        open("parking.txt", "w") do |pw|
          while pl=pr.gets
    	if /%DATE%/ =~ pl then
    	  pw.puts Time.now.strftime("%Y年%m月%d日")
    	else
    	  pw.print pl
    	end
          end
        end
      end
      STDERR.puts "本日分の駐車券を作成しました。"
      STDERR.puts "parking.txtを印刷して利用してください。"
    rescue
      STDERR.puts "parking.tmplを用意したうえで、。"
      STDERR.puts "parking.txtに結果が書き出せるようにしておいてください。"
      STDERR.puts "よろしう。"
    end
    
  6. customreg.rb

    #!/usr/local/bin/ruby
    name = []			# 商品名を配列にいれる
    value = []			# 価格を配列にいれる
    total = 0			# 価格の合計
    nitem = 0			# 読み取った商品の数
    
    begin
      # テンプレートファイルを開く
      open("register.tmpl", "r") do |tp|
        while true
          STDERR.print "商品名は?: "
          item = gets
          if item == nil then		# 入力終わりなら gets はnilを返す
    	break
          end
          name[nitem] = item.chomp!
          STDERR.print "おいくら?: "
          price = gets.to_i
          value[nitem] = price
          total += price
          nitem += 1
        end
    
        i=0
        puts ""				# 改行するだけ
        while template=tp.gets
          if /%SUMMARY%/ =~ template
    	# テンプレートファイルに %SUMMARY% という行があったら
    	# その部分の代わりに買い物情報を出力
    	while i<nitem 
    	  printf("%-14s %5d円\n", name[i], value[i])
    	  i += 1
    	end
    	puts "- "*17
    	print "お買い上げありがとうございました。\n"
    	printf("合計は%6d円です。\n", total)
          elsif /%DATE%/ =~ template then
    	puts Time.now.strftime("%Y年%m月%d日")
          else
    	print template
          end
        end
      end
    rescue
      STDERR.puts "register.tmplを用意してからプログラムを起動してください。"
    end
    

練習問題 8

  1. 10進数2進数16進数7進数
    2005111110101017d55563
    421010102a60
    3054101111101110bee11622
    19411000010c2365
  2. Japan!
    0x4a0x61 0x700x610x6e0x21

練習問題 9

  1. last1c.rb

    #!/usr/local/bin/ruby
    while l=gets
      print l[-2..-1]
    end
    
  2. hyphen.rb

    #!/usr/local/bin/ruby
    while l=gets
      l.chomp!
      print l+"-"*(80-l.length)+"\n"
    end
    
  3. randq.rb

    #!/usr/local/bin/ruby
    m = ["世界で一番高い山は?", "日本で一番高い山は?",
      "エトセトラ、を表す3文字の略語は?",
      "高速道路で料金を自動的に払うシステムの略称は?"]
    srand()
    puts m[rand(m.length)]
    
  4. qpod.rb

    #!/usr/local/bin/ruby
    question=[]
    answer=[]
    n = 0
    begin
      open("quiz.dat", "r") do |q|
        while line=q.gets
          question[n] = line.chomp
          answer[n] = q.gets.chomp
          n+=1
        end
      end
    rescue
      STDERR.puts "quiz.datに問題&解答集を用意してね"
      exit(0)
    end
    
    i=0
    while i<n
      printf("問題: %s(答を見るには[Return])\n", question[i])
      gets				# [Return]で先に進む
      printf("答: %s\n", answer[i])
      i+=1
    end
    
  5. shuffle.rb

    #!/usr/local/bin/ruby
    x = (0..52).collect
    i=0
    srand()				# 乱数の種を初期化
    while i<x.length
      t=rand(x.length)		# 交換相手を探す
      tmp=x[i]
      x[i] = x[t]
      x[t] = tmp
      i += 1
    end
    p x				# xを配列のまま出力
    
  6. qpod-shuffle.rb

    #!/usr/local/bin/ruby
    question=[]
    answer=[]
    n = 0
    begin
      open("quiz.dat", "r") do |q|
        while line=q.gets
          question[n] = line.chomp
          answer[n] = q.gets.chomp
          n+=1
        end
      end
    rescue
      STDERR.puts "quiz.datに問題&解答集を用意してね"
      exit(0)
    end
    
    # シャッフルする
    srand()
    i=0
    while i<question.length
      t=rand(question.length)
      # まず、question[i]とquestion[t]を交換
      tmp=question[i]
      question[i] = question[t]
      question[t] = tmp
      # answer[i]とanswer[t]を交換
      tmp=answer[i]
      answer[i] = answer[t]
      answer[t] = tmp
      i+=1
    end
    
    i=0
    while i<n
      printf("問題: %s(答を見るには[Return])\n", question[i])
      gets				# [Return]で先に進む
      printf("答: %s\n", answer[i])
      i+=1
    end
    
  7. janken.rb

    #!/usr/local/bin/ruby
    
    janken = ["グー", "チョキ", "パー"]
    while true
      STDERR.puts "じゃんけんしましょ、"
      STDERR.print "あなたの手は? [グーなら0、チョキなら1、パーなら2]: "
      j = gets
      if j == nil then
        break
      end
      human=j.to_i
      if human < 0 || human > 2 then
        STDERR.puts "ちゃんと出してね。0, 1, 2のどれかだよ。"
        redo
      end
      com = rand(3)
      printf("あなた「%s」 : 「%s」わたし\n",
    	 janken[human], janken[com])
      if human==0 && com==1 || human==1 && com==2 || human==2 && com==0 then
        puts "があ〜ん負けちゃったー! 強いのね。"
      elsif human==com then
        puts "おっと引き分けだ。仲良しこよし。"
      else
        puts "やったー、勝ったー! よわよわじゃん。"
      end
      STDERR.print "もういちど"
    end
    STDERR.puts "\nあらもうおしまい? さようなら!"
    
  8. jankenstat.rb

    #!/usr/local/bin/ruby
    
    win=lose=draw=0			# 勝ち、負け、引き分け
    janken = ["グー", "チョキ", "パー"]
    while true
      STDERR.puts "じゃんけんしましょ、"
      STDERR.print "あなたの手は?"
      STDERR.print "[グーなら0、チョキなら1、パーなら2]: "
      j = gets
      if j == nil then
        break
      end
      human=j.to_i
      if human < 0 || human > 2 then
        STDERR.puts "ちゃんと出してね。0, 1, 2のどれかだよ。"
        redo
      end
      com = rand(3)
      printf("あなた「%s」 : 「%s」わたし\n",
    	 janken[human], janken[com])
      if human==0 && com==1 ||
          human==1 && com==2 ||
          human==2 && com==0 then
        puts "があ〜ん負けちゃったー! 強いのね。"
        win += 1
      elsif human==com then
        puts "おっと引き分けだ。仲良しこよし。"
        draw += 1
      else
        puts "やったー、勝ったー! よわよわじゃん。"
        lose += 1
      end
      STDERR.print "もういちど"
    end
    STDERR.puts "\nあらもうおしまい? さようなら!"
    printf("あなたの戦績: %d勝%d敗%d分け\n",
           win, lose, draw)
    

練習問題 10

  1. 数学的関数f(x)に相当するメソッド。

    def f(x)
      x**2+3*x-1
    end
    
  2. rectangleメソッド。

    def rectangle(width, height)
      width*height
    end
    
  3. leapメソッド。

    def leap(y)
      if y%4!=0 || y%100==0 && y%400!=0 then
        365
      else
        366
      end
    end
    

    このロジックは、閏年判定に用いられる。

  4. tagifyメソッド。

    def tagify(element, content)
      "<"+element+">"+content+"</"+element+">"
    end
    
  5. pre.rb

    #!/usr/local/bin/ruby
    
    def tagify(element, content)
      "<"+element+">"+content+"</"+element+">"
    end
    
    while sentence=gets
      printf("%s\n", tagify("pre", sentence.chomp!))
    end
    
  6. sflメソッド。

    def sfl(arr)
      tmp=arr[0]
      arr[0]=arr[-1]
      arr[-1]=tmp
      arr
    end
    

練習問題 11

  1. プログラムの前半と後半に分けて例を載せる。前半には エラー処理を記述する。

    #!/usr/local/bin/ruby
    
    if ARGV[0] == nil then
      STDERR.puts "出力回数を指定してください。"
      STDERR.puts "例: ./nhello.rb 5"
      exit(1)
    end
    

    後半は、ARGV[0]を整数に直して(to_i)、 その回数だけ puts "Hello, world!" する。様々な方法があるので 以下のその1〜その5のどれかを選択する。

    # その1
    ARGV[0].to_i.times do
      puts "Hellow, wowrld!"
    end
    # その2
    ARGV[0].to_i.downto(1) do |i|
      puts "Hellow, wowrld!"
    end
    # その3
    1.upto(ARGV[0].to_i) do |i|
      puts "Hellow, wowrld!"
    end
    # その4
    for i in 1..(ARGV[0].to_i)
      puts "Hellow, wowrld!"
    end
    # その5
    1.step(ARGV[0].to_i, 1) do |i|
      puts "Hellow, wowrld!"
    end
    
  2. copy.rb

    #!/usr/local/bin/ruby
    
    if ARGV[1] == nil
      STDERR.puts "ファイルをコピーします。"
      STDERR.puts "./copy.rb コピー元 コピー先"
      exit(1)
    end
    
    # ARGV[0]がコピー元ファイル。読めるかチェック。
    if test(?r, ARGV[0]) then
      open(ARGV[0], "r") do |src|
        open(ARGV[1], "w") do |dst|
          while s=src.gets
    	dst.print s
          end
        end
      end
    end
    
  3. backup.rb

    #!/usr/local/bin/ruby
    
    if ARGV[0] == nil
      STDERR.puts "ファイルをバックアップします。"
      STDERR.puts "./backup.rb ファイル名"
      exit(1)
    end
    
    # ***** (A) *****
    # ARGV[0]がコピー元ファイル。読めるかチェック。
    if !test(?r, ARGV[0]) then
      STDERR.printf("%s ファイルは読めません\n", ARGV[0])
      exit(2)
    end
    n=1			# 拡張子。1からスタート。
    while true
      # 元の名前とnからバックアップファイル名を生成
      backup = sprintf("%s.%d", ARGV[0], n)
      if !test(?r, backup)	# 存在しなければ
        break		# ループを抜ける
      end
      n += 1
    end
    
    open(ARGV[0], "r") do |src|
      open(backup, "w") do |dst|
        while s=src.gets
          dst.print s
        end
      end
    end
    STDERR.printf("[%s] --> [%s]\n", ARGV[0], backup)
    # ***** (B) *****
    
  4. 前問のbackup.rbのソース中にある 「***** (A) *****」の部分に

    while ARGV[0]

    を、「***** (B) *****」の部分に

      ARGV.shift
    end

    を追加すれば良い。(A)と(B)で囲まれた部分は、 適宜インデントし直すこと。

練習問題 12

  1. pricelist.rb

    #!/usr/local/bin/ruby
    prlist={}
    while entry=gets
      if /(\S+)=(\d+)/ =~ entry
        prlist[$1] = $2.to_i
      end
    end
    
    $KCODE='e'
    p prlist
    
  2. aefreq.rb

    #!/usr/local/bin/ruby
    
    freq=Hash.new(0)
    
    while s=gets
      for ch in s.chomp!.split(//)
        freq[ch] += 1
      end
    end
    
    puts "---+--------"
    for ch, count in freq do
      if /[a-e]/ =~ ch
        printf(" %s | %3d\n", ch, count)
     end
    end
    puts "---+--------"
    

練習問題 13

  1. kokugo-rank.rb のうち、

    for student in point.keys.sort {|x, y|
        point[x][0] <=> point[y][0]
      }.reverse
    

    の部分を、以下のように変えれば良い。

    for student in point.keys.sort {|x, y|
        point[x][1] <=> point[y][1]
      }.reverse
    
  2. 前問の該当部分を以下のように変えれば良い。

    for student in point.keys.sort {|x, y|
        point[x][0]+point[x][1] <=> point[y][0]+point[y][1]
      }.reverse
    

    ただし、この場合sortメソッドが並べ換えのときに何度も足し算する ことになり効率が良くない。このような場合は、データの読み込み時にあ らかじめ合計値を計算し、配列要素として追加しておくのがよい。そうす るためには、kokugo-rank.rb

    if /(\S+)\s+(\d+)\s+(\d+)/ =~ yline
        point[$1] = [$2.to_i, $3.to_i]
    end

    の部分を、

    if /(\S+)\s+(\d+)\s+(\d+)/ =~ yline
        point[$1] = [$2.to_i, $3.to_i, $2.to_i+$3.to_i]
    end

    と変更し、並べ換えの部分を

    for student in point.keys.sort {|x, y|
        point[x][2] <=> point[y][2]
      }.reverse
    

    とすればよい。

  3. jslash.rb

    #!/usr/local/bin/ruby
    line=[]
    while l=gets
      line << l.chomp!
    end
    puts line.join("/")
    
  4. wordsplit.rb

    #!/usr/local/bin/ruby
    while l=gets
      l.chomp!
      for word in l.split(/[., \t\n]+/)
        if word != "" then
          puts word
        end
      end
    end
    
  5. freq.rb

    #!/usr/local/bin/ruby
    
    freq=Hash.new(0)
    
    while s=gets
      for ch in s.chomp!.split(//)
        freq[ch] += 1
      end
    end
    
    puts "---+--------"
    for ch, in freq.keys.sort{|x, y| freq[y] <=> freq[x]}
      if /[a-z]/ =~ ch
        printf(" %s | %3d\n", ch, freq[ch])
      end
    end
    puts "---+--------"
    
  6. wordfreq.rb

    #!/usr/local/bin/ruby
    
    freq=Hash.new(0)
    
    while l = gets
      for word in l.chomp!.split(/[,. \t]+/)
        if word != ""
          freq[word] += 1
        end
      end
    end
    
    puts "--------------+--------"
    for word in freq.keys.sort{|x, y| freq[y] <=> freq[x]}
      if /[a-z]/ =~ word
        printf(" %-12s | %3d\n", word, freq[word])
      end
    end
    puts "--------------+--------"
    

練習問題 14

  1. age.rb

    #!/usr/local/bin/ruby
    def age(thisyear, birthyear)
      if thisyear==birthyear
        0
      else
        1+age(thisyear-1, birthyear)
      end
    end
    
    STDERR.print "生まれた西暦年は?: "
    printf("誕生日後は%d歳ですね\n",
           age(Time.now.year, gets.to_i))
    
  2. hanoi.rb

    #!/usr/local/bin/ruby
    
    def hanoi(n, from, to, work)
      if n == 1
        printf("%d番の円盤 を %s から %s に移動しなさい\n", n, from, to)
      else
        hanoi(n-1, from, work, to)
        printf("%d番の円盤 を %s から %s に移動しなさい\n", n, from, to)
        hanoi(n-1, work, to, from)
      end
    end
    
    if ARGV[0] == nil
      STDERR.puts "ハノイの塔の最初の板の数を指定してください。"
      STDERR.puts "例: ./hanoi.rb 5"
      exit 0
    end
    
    n=ARGV[0].to_i
    hanoi(n, "A", "B", "C")
    

  3. afind.rb

    #!/usr/local/bin/ruby
    
    if ARGV[0] == nil
      ARGV.push(".")
    end
    
    def afind(path)
      # [2..-1]で0番目、1番目の要素を除去した配列が得られる
      for f in Dir.entries(path)[2..-1].sort
        if test(?d, path+"/"+f)
          # fがディレクトリなら再帰的に検索
          afind(path+"/"+f)
        end
        if /^a/ =~ f then
          printf("%s/%s\n", path, f)
        end
      end
    end
    
    for dir in ARGV
      afind(dir)	# コマンドライン引数全部に対して繰り返す
    end
    

練習問題 15

  1. 13.6のwordfreq.rb

    l.chomp!

    の部分を、

    l.chomp!.downcase

    に変えれば良い。

  2. msg1.rb

    #!/usr/local/bin/ruby
    ff="msg1.txt"
    if !test(?r, ff)
      STDERR.printf("%s にメッセージを入れといてね\n", ff)
      exit(1)
    end
    
    STDERR.print "戦士よ、汝の名は?: "
    name=gets.chomp
    
    open(ff, "r") do |m|
      while msg=m.gets
        print msg.gsub(/%NAME%/){name}
      end
    end
    
  3. pos.rb

    #!/usr/local/bin/ruby
    name = []			# 商品名を配列にいれる
    value = []			# 価格を配列にいれる
    total = 0			# 価格の合計
    nitem = 0			# 読み取った商品の数
    
    
    STDERR.print "ポイント倍率は?: "
    pointrate=gets.chomp
    
    begin
      # テンプレートファイルを開く
      open("register.tmpl", "r") do |tp|
        while true
          STDERR.print "商品名は?: "
          item = gets
          if item == nil then		# 入力終わりなら gets はnilを返す
    	break
          end
          name[nitem] = item.chomp!
          STDERR.print "おいくら?: "
          price = gets.to_i
          value[nitem] = price
          total += price
          nitem += 1
        end
    
        i=0
        puts ""				# 改行するだけ
        while template=tp.gets
          if /%SUMMARY%/ =~ template
    	# テンプレートファイルに %SUMMARY% という行があったら
    	# その部分の代わりに買い物情報を出力
    	while i<nitem 
    	  printf("%-14s %5d円\n", name[i], value[i])
    	  i += 1
    	end
    	puts "- "*17
    	print "お買い上げありがとうございました。\n"
    	printf("合計は%6d円です。\n", total)
          else
    	template.gsub!(/%DATE%/){
    	  Time.now.strftime("%Y年%m月%d日")
    	}
    	template.gsub!(/%P%/){pointrate}
    	print template
          end
        end
      end
    rescue
      STDERR.puts "register.tmplを用意してからプログラムを起動してください。"
    end
    

    customreg.rbとの違いを下線 で示した。

  4. exam.rb

    #!/usr/local/bin/ruby
    
    pts={}
    summary = gets.chomp.split(/,/)	# 科目名リスト
    summary << "合計"	 # 科目名の末尾を「合計」に
    nsubj = summary.length-1 # 科目数はsummaryの要素数-1
    
    while line=gets
      x = line.split(/,/)	# x[1]〜x[-1]に各科目の点が入る(文字列)
      name = x[0]		# x[0]には氏名
      pts[name] = x[1..-1]	# pts[name]にx[1]〜x[-1]をコピー
      sum = 0		# 合計点用
      0.upto(pts[name].length-1) do |j|
        # 数値に変換しておく
        pts[name][j] = pts[name][j].to_i
        sum += pts[name][j]
      end
      pts[name] << sum	# 合計点を配列末尾に追加
    end
    
    printf(" %-14s ", summary[0])
    for s in summary[1..-1]
      printf("| %4s ", s)	# 科目名のヘッダ出力
    end
    puts ""
    puts "-"*16+"+------"*nsubj	# 区切り線
    # 合計点の高い順にソート
    for i in pts.keys.sort{
        |x, y| pts[y][-1]<=>pts[x][-1]
      }
      printf(" %-14s ", i)
      for p in pts[i]
        printf("| %4d ", p)
      end
      puts ""
    end
    puts "-"*16+"+------"*nsubj	# 区切り線
    
  5. exam.rbの末尾に以下の内容を追加すれば良い。

    # 各科目の平均を計算
    sum=Array.new
    avg=Array.new
    0.upto(nsubj-1) do |i|
      sum[i]=0.0
      # 人数分可算
      for student in pts.keys
        sum[i] += pts[student][i]
      end
      avg[i] = sum[i]/pts.length
    end
    
    stddev=Array.new
    # 各科目の標準偏差を計算
    0.upto(nsubj-1) do |i|
      v=0.0		# 分散の計算
      for student in pts.keys
        v += (pts[student][i]-avg[i])**2
      end
      # (標本数-1)で割ったものの平方根が標準偏差
      stddev[i] = Math.sqrt(v/(pts.length-1))
    end
    
    printf(" %-14s ", "平均")
    for p in avg
      printf("|%5.1f ", p)
    end
    puts ""
    printf(" %-14s ", "標準偏差")
    for p in stddev
      printf("|%5.1f ", p)
    end
    puts ""
    puts "-"*16+"+------"*nsubj	# 区切り線
    

練習問題 16

  1. 5pan.rb

    #!/usr/local/bin/ruby
    
    menu=["あんパン", "クリームパン", "メロンパン",
    "うぐいすパン", "ずんだパン"]
    
    srand
    0.upto(menu.length-1) do |i|
      j = rand(menu.length)
      tmp = menu[i]
      menu[i] = menu[j]
      menu[j] = tmp
    end
    
    puts "今日は、"
    print menu.join("を食べて、\n")
    puts "を食べてしめましょう。"
    
  2. その都度ogg123コマンドを呼ぶ場合。

    ogg-shuffle.rb

    #!/usr/local/bin/ruby
    srand
    0.upto(ARGV.length-1) do |i|
      j = rand(ARGV.length)
      tmp = ARGV[i]
      ARGV[i] = ARGV[j]
      ARGV[j] = tmp
    end
    
    for o in ARGV
      system("ogg123", o)
    end
    

    ogg123コマンドにoggファイルを全て渡す場合。

    ogg-shuffle.rb

    #!/usr/local/bin/ruby
    srand
    0.upto(ARGV.length-1) do |i|
      j = rand(ARGV.length)
      tmp = ARGV[i]
      ARGV[i] = ARGV[j]
      ARGV[j] = tmp
    end
    
    system("ogg123 "+ARGV.join(" "))
    

yuuji@example.org
Fingerprint16 = FF F9 FF CC E0 FE 5C F7 19 97 28 24 EC 5D 39 BA
HIROSE Yuuji - ASTROLOGY / BIKE / EPO / GUEST BOOK / YaTeX [Tweet]