Ruby で CSV を処理するときに、空行を無視するために empty?
を使って下記のように書いていました。
require "csv"
CSV.foreach("foo", headers: :first_row) do |row|
next if row.empty?
p row
end
headers
を指定した場合、行は CSV::Row
で表現されますが、Ruby 2.6 からは CSV::Row#empty?
は false
を返すようです。
#!/bin/sh
RBENV_VERSION=2.5.1 ruby -rcsv <<EOS
CSV.parse("\n", headers: %w(a)) do |row|
p row.empty? # true
end
EOS
RBENV_VERSION=2.6.4 ruby -rcsv <<EOS
CSV.parse("\n", headers: %w(a)) do |row|
p row.empty? # false
end
EOS
p row
などでみてみると、2.5 ではフィールドの情報を持っていないのに対し、2.6 ではフィールドの情報を持っています。
#!/bin/sh
RBENV_VERSION=2.5.1 ruby -rcsv <<EOS
CSV.parse("\n", headers: %w(a)) do |row|
p row # #<CSV::Row>
p row.to_a # []
p row.to_hash # {}
end
EOS
RBENV_VERSION=2.6.4 ruby -rcsv <<EOS
CSV.parse("\n", headers: %w(a)) do |row|
p row # #<CSV::Row "a":nil>
p row.to_a # [["a", nil]]
p row.to_hash # {"a"=>nil}
end
EOS
ドキュメント には、empty?
などは Array に delegate されると記載があります。上記のように 2.6 では to_a
の返り値が空ではないので empty?
が false
を返すようです。
空行の読み飛ばしは CSV::Row#empty?
を使うのではなく、CSV.new
等のオプションに skip_blanks: true
を指定するのがよさそうです (2.5, 2.6 とも)。