Hatena::Grouprubyist

krystal: プログラミング超初心者(文系)

2008-12-01 (Mon)たのしいRuby練習問題

P230 - クラスStringIOを定義しよう

17:53

  • 与えられた文字列に対して、IOクラスのようにgetsreadができるオブジェクトのクラスStringIOを定義しよう
  • このクラスは以下のような使い方を想定している
sio = StringIO.new("密林\n嘘\n赤と黒\n罠\n罪")
p sio.gets  #=> "密林\n"
p sio.gets  #=> "嘘\n"
p sio.gets  #=> "赤と黒\n"
sio.rewind  
p sio.gets  #=> "密林\n"

このように定義した

class StringIO
  def StringIO.gets(string)
    ary = string.split("\n")
    string_length = string.split("\n").size
    string_length.times{|x|ary.shift
    }
  end
  
  def StringIO.rewind
    return string
  end

end
sio = StringIO.new("密林\n\n赤と黒\n\n")
p sio.gets  #=> "密林\n"
p sio.gets  #=> "嘘\n"
p sio.gets  #=> "赤と黒\n"
sio.rewind  
p sio.gets  #=> "密林\n"

修正

  • ↑の書き方だと既存のStringIOクラスのメソッドをそのまま使ってるだけ
  • いろんな方に質問したり、正解を参考にしたりした
class MyIO
  def initialize(string = "")
    @string = string
    @position = 0
  end
  
  def read(num)
    if num < 0
      return false
    end

    show = @string[@position, num]
    @position += num 
    if @position > @string.size
      @position = @string.size
    end
      
    show
  end
  
  def gets
    if @position >= @string.size
      return nil
    end

    pos = @string.index("\n", @position)
    if pos == nil
      @string.size
    end
      ret = @string[@position..pos]
      @position = pos + 1
      return ret
  end

  def rewind
    @position = 0
  end
  
end

mio = MyIO.new("密林\n\n赤と黒\n\n")
p mio.gets      #=> "密林\n"
p mio.gets      #=> "嘘\n"
p mio.gets      #=> "赤と黒\n"
p mio.gets      #=> "罠\n"
p mio.read(5)   #=> "罪"
p mio.read(3)   #=> ""
mio.rewind 
p mio.read(2)   #=>"密"

あとこういうのも書いた

  • splitshiftを使って書いたもの
  • 質問の意図はこれじゃないけど、せっかく書いたからアップ
class MyIO
  def initialize(string)
    @string = string
    @ary = @string.split("\n")
  end
  
  def get_word
    @ary.shift
  end
  
  def rewind
    @ary = @string.split("\n")
  end
end

mio = MyIO.new("密林\n\n赤と黒\n\n")

p mio.get_word   #=>  "密林"
p mio.get_word   #=>  "嘘"
p mio.get_word   #=>  "赤と黒"
mio.rewind
p mio.get_word   #=>  "密林"

えぬえぬ 2008/12/01 21:01 毎回、配列に split して shift すると遅くならないの?

entottoentotto 2008/12/02 18:16 上のクラスを irb で試したら、エラーになりました。

irb(main):014:0> sio = StringIO.new("aa\nbb\ncc\ndd\nss")
ArgumentError: wrong number of arguments (1 for 0)
from (irb):14:in `initialize'
from (irb):14:in `new'
from (irb):14
from :0

あと、仕様では gets に引数を渡してないのに、コードでは引数を取るメソッドなのも気になります。

krystalkrystal 2008/12/02 20:30 >えぬさん
コメントありがとうございます。
スピードのことまったく考慮していませんでした..
早くなる方法のヒントをいただければと思います。

>entottoさん
エラーですか!?
確かにgetsに引数を渡してしまってます。
修正します。

holysugarholysugar 2008/12/03 00:11 というか、StringIO.gets を定義したのに、StringIO#gets を呼んでもできたことにならないのでは。
標準ライブラリの StringIO のメソッドを呼んでいるだけですよね?

とりあえず StringIO のマニュアルを読んだあとに、練習に必要なら、StringIO とは別のクラスを定義してみてはいかがでしょうか。

krystalkrystal 2008/12/04 20:54 >holysugarさん
コメントありがとうございます。
実は既存のものをそのまま使ってしまったということですね。
修正しました。ご指摘ありがとうございます。

ゲスト



トラックバック - http://rubyist.g.hatena.ne.jp/krystal/20081201