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"