rubyベストプラクティスchapter7.4

とりあえず写経。。。
読み込みを色々な文字にしたり、読み込むバイトを色々変えてやってみる。

元はこれ

File.open("./hello.txt") { |f|
  loop do
    break if f.eof?
    chunk = "CHUNK: #{f.read(5)}"  #ここの5を色々変える
    puts chunk unless chunk.empty?
  end
}

で読み込むhello.txtを

hello

にした時

ruby read_hello.rb
CHUNK: hello
CHUNK: 

まぁあたり前です。

read(3)にした時

ruby read_hello.rb
CHUNK: hel
CHUNK: lo

これもまぁ当り前

次はhello.txtを

こんにちわ

にした時

ruby read_hello.rb
CHUNK: こ
CHUNK: �に
CHUNK: ��わ
CHUNK: 

おぉ!なんか変だ!

次はread(3)にする。

ruby read_hello.rb
CHUNK: こ
CHUNK: ん
CHUNK: に
CHUNK: ち
CHUNK: わ
CHUNK: 

ちょっと脱線。
本でいいたいのはマルチバイトのエンコーディングの場合単純に2バイト1文字とか決めうちできないってこと。

そういうことを前提として1文字をどのように特定しているのかっていうのをcsvライブラリのソースで説明している。

def read_to_char(bytes)
  return "" if @io.eof?
  data = @io.read(bytes)
  begin
    encoded = encode_str(data)
    railse unless ecnoded.valid_encoding?    #(1)
    return encoded                           #(3)
  rescue
    if @io.eof? or data.size >= bytes + 10   #(4)
      return data
    else                                     #(2)
      data += @io.read(1)
      retry
    end
  end
end

@ioってインスタンス変数がチャンク化したい文字のかたまり(csvライブラリではなんらかのioオブジェクト)で、
指定バイト数分読み込んだ文字列が文字として有効かっていうのをvalid_encoding?で確認している。(1)
有効な文字列でない場合、読み込みバイト数を1つ増やしてもう一度有効な文字列かを確認する。(2)
有効な文字列の場合その文字列を返す。(3)
文字列の塊(@io)が終端にたっするか、読み初めて10バイトを越えた場合はそこまで読み込んだ文字列を返す。(4)

データをチャンク化したい場合は

1. 1バイトずつ文字列を読んでいって
2. 読み込んだものをvalid_encoding?で有効な文字列かを確認して
3. 有効でない場合、さらに1バイト先まで読み込んで1-2をやりなおし。
4. 有効な文字列の場合それが返却値
といった流れになると思われます。


Rubyベストプラクティス -プロフェッショナルによるコードとテクニック

Rubyベストプラクティス -プロフェッショナルによるコードとテクニック