Edited at

Ruby の CSV クラスで CSV::MalformedCSVError になった行を得る

More than 3 years have passed since last update.

CSV クラスのインスタンスは、CSV データを持つ IO オブジェクトを @io というインスタンス変数で保持しています。

また CSV クラスのインスタンスはいくつかの IO メソッドを @io に委譲しています。


csv.rb

  ### IO and StringIO Delegation ###

extend Forwardable
def_delegators :@io, :binmode, :binmode?, :close, :close_read, :close_write,
:closed?, :eof, :eof?, :external_encoding, :fcntl,
:fileno, :flock, :flush, :fsync, :internal_encoding,
:ioctl, :isatty, :path, :pid, :pos, :pos=, :reopen,
:seek, :stat, :string, :sync, :sync=, :tell, :to_i,
:to_io, :truncate, :tty?


ということで、以下の様な感じで malformed な(物理)行を抽出する事ができました。


test.rb

require 'csv'

require 'tempfile'

Tempfile.create('malformed-csv') do |temp|
temp.write(<<EOF)
id,name,value
"1","NAME","VALUE"
"2","NAME","VALUE"
"3",NAME"","VAL
UE"
EOF
temp.flush

processed_position = 0
begin
csv = CSV.open(temp.path)
csv.each do |_|
processed_position = csv.pos
end
rescue CSV::MalformedCSVError
aborted_position = csv.pos
io = csv.to_io
io.seek(processed_position)
p io.read(aborted_position - processed_position)
end
end

__END__
"\"3\",NAME\"\",\"VAL\n"