0

假设我有一个格式如下的文件。

date|time|account
2010-01-01|07:00:00|A1
2010-01-01|07:00:01|A2
....

假设我有以下功能。

def ReadLongFile(longFile)
  CSV.foreach(longFile, :headers => true, :col_sep => '|') do |row|
    p row.to_hash
  end
end

我喜欢这个函数,因为它允许我将每一行存储为一个散列,其中标题条目是键,行条目是相应的值。但是,修改它以便我可以验证标题是否包含正确条目的最有效方法是什么?我正在考虑两种选择。首先,我可以打开另一个函数并检查第一行。其次,我可以在函数内进行检查,但它会在每次迭代时执行检查。

4

1 回答 1

1

我建议使用CSV::header_row函数来执行检查,如果它不是您所期望的,则会引发错误。就像是:

def ReadLongFile(longFile)
  CSV.foreach(longFile, :headers => true, :return_headers => true, :col_sep => '|') do |row|
    if row.header_row? then 
      raise ArgumentError, "Bad headers" unless header_sane?(row) 
    end
    # Otherwise do the processing
  end
end

您的实现header_sane?将执行您需要的验证,以确保文件符合您的预期。如果可以从中恢复,您的调用代码可以挽救 ArgumentError,或者只是让它失败:-)

注意:更新以反映以下评论中指出的错误。请务必在调用CSV::foreach时设置 :return_headers 选项。

如果您担心调用 header_row 的最小开销?对于每个行条目,您可以构建一个 CSV 实例并使用shift在继续之前手动检查第一行。例如:

def ReadLongFile(longFile)
   File.open(longFile) do |file|
     reader = CSV.new(file, {:col_sep => '|', :headers => true, :return_headers => true})
     header_row = reader.shift
     raise ArgumentError, "Bad file headers" unless header_sane?(header_row)
     reader.each do |row|
       p row
     end  
   end  
end

如上所述实现,以下行为成立:

[4] pry(main)> def header_sane? row
[4] pry(main)*   true
[4] pry(main)* end  
=> nil
[5] pry(main)> ReadLongFile("file.csv")
#<CSV::Row "date":"2010-01-01" "time":"07:00:00" "account":"A1">
#<CSV::Row "date":"2010-01-01" "time":"07:00:01" "account":"A2">
=> nil
[6] pry(main)> def header_sane? row
[6] pry(main)*   false
[6] pry(main)* end  
=> nil
[7] pry(main)> ReadLongFile("file.csv")
ArgumentError: Bad file headers
from (pry):7:in `block in ReadLongFile'
于 2013-05-10T18:30:18.277 回答