Ruby CSV 不读取带引号的字符串中的逗号格式数字

rad*_*hop 1 ruby csv ruby-on-rails

我在 Rails 应用程序中使用 ruby​​ 的 CSV 类(ruby 2.1.5)从上传的 csv 文件加载记录。用户正在使用“另存为”从 Excel 创建 csv 文件,并且根据数字的格式,它们可能会保存为带逗号的带引号的字符串——在这种情况下,逗号后面的数字部分被删除。

如果输入值是"3,500",则3500应该保存,但它是3

我意识到可以在 Excel 中清理它,但它似乎也应该很容易处理(如果我不得不告诉用户程序无法处理这种基本情况,我会从用户那里得到一个主要的 WTF。 ) 此外,由于 csv 文件的标题与数据库中的列名称匹配,因此我不必编写特定于列的处理程序 - 我只需进行属性分配。我希望保持这种状态,因为我的受影响列比我在示例中包含的列要多得多。

输入记录:

recordid,valcurrent,valdate
11015,"3,500",6/7/2013
Run Code Online (Sandbox Code Playgroud)

处理功能

def import_csv(file)
  CSV.foreach(file.path, headers: true, header_converters: :symbol, skip_blanks: true, converters: :all) do |row|
    # hash the input row 
    row_hash = row.to_hash
    # create a new row with the hash in original_record
    fl = self.forecast_lines.create(original_record: row_hash.to_s)
    # write the hash to the record attributes
    fl.attributes = row_hash
    fl.save
  end
end
Run Code Online (Sandbox Code Playgroud)

原始记录哈希:

Original record: {:recordid=>"11015", :valcurrent=>"3,500", :valdate=>"6/7/2013"} 
Run Code Online (Sandbox Code Playgroud)

valcurrent 的数据类型是 float。但是保存到数据库中的 valcurrent 值不是3500.0,而是3.0

dar*_*ryn 5

您可以添加一个自定义转换器来正确处理您的数字列。不确定这是否涵盖了所有可能的格式选项,但它看起来像这样:

创建一个 lambda:

comma_numbers = ->(s) {(s =~ /^\d+,/) ? (s.gsub(',','').to_f) : s}
Run Code Online (Sandbox Code Playgroud)

将其添加到您的转换器中:

CSV::Converters[:comma_numbers] = comma_numbers
Run Code Online (Sandbox Code Playgroud)

新转换器不包含在 converters::all 中,因此将其添加为数组:

converters: [:all, :comma_numbers]
Run Code Online (Sandbox Code Playgroud)