Ruby CSV 不读取 comma-formatted 引号字符串中的数字
Ruby CSV not reading comma-formatted numbers in quoted strings
我在 Rails 应用程序中使用 ruby 的 CSV class (ruby 2.1.5) 从上传的 csv 文件加载记录。用户正在使用 "Save As" 从 Excel 创建 csv 文件,并且根据数字的格式,它们可能被保存为带引号的带逗号的字符串——在这种情况下,数字后面的部分逗号被删除。
如果输入值是"3,500"
,那么3500
应该被保存,而是3
。
我意识到可以在 Excel 中清理它,但它似乎也应该很容易处理(如果我必须告诉用户,我会从用户那里得到一个主要的 WTF程序无法处理这种基本情况。)此外,由于 csv 文件的 headers 与数据库中的列名相匹配,我不必编写 column-specific 处理程序 - 我只是做一个属性任务。我希望保持这种状态,因为受影响的列比我在示例中包含的列要多得多。
输入记录:
recordid,valcurrent,valdate
11015,"3,500",6/7/2013
处理函数
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
原始记录哈希:
Original record: {:recordid=>"11015", :valcurrent=>"3,500", :valdate=>"6/7/2013"}
valcurrent 的数据类型为 float。但是保存到数据库中的 valcurrent 值不是 3500.0
,而是 3.0
.
问题不在于 CSV,而在于 Ruby 如何将字符串转换为浮点数。
在Ruby中:
"3,500".to_f => 3.0
这就是将 3.0 存储在数据库中的原因。您应该更改 import_csv 方法来处理逗号。
此外,我认为您不应该在创建中执行 row_hash.to_s。这样的 Create 方法接受哈希作为参数。
您可以添加一个自定义转换器来正确处理您的数字列。不确定这是否涵盖了所有可能的格式选项,但它看起来像这样:
创建一个 lambda:
comma_numbers = ->(s) {(s =~ /^\d+,/) ? (s.gsub(',','').to_f) : s}
将其添加到您的转换器中:
CSV::Converters[:comma_numbers] = comma_numbers
新转换器未包含在转换器中::all 所以将其添加为数组:
converters: [:all, :comma_numbers]
我在 Rails 应用程序中使用 ruby 的 CSV class (ruby 2.1.5) 从上传的 csv 文件加载记录。用户正在使用 "Save As" 从 Excel 创建 csv 文件,并且根据数字的格式,它们可能被保存为带引号的带逗号的字符串——在这种情况下,数字后面的部分逗号被删除。
如果输入值是"3,500"
,那么3500
应该被保存,而是3
。
我意识到可以在 Excel 中清理它,但它似乎也应该很容易处理(如果我必须告诉用户,我会从用户那里得到一个主要的 WTF程序无法处理这种基本情况。)此外,由于 csv 文件的 headers 与数据库中的列名相匹配,我不必编写 column-specific 处理程序 - 我只是做一个属性任务。我希望保持这种状态,因为受影响的列比我在示例中包含的列要多得多。
输入记录:
recordid,valcurrent,valdate
11015,"3,500",6/7/2013
处理函数
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
原始记录哈希:
Original record: {:recordid=>"11015", :valcurrent=>"3,500", :valdate=>"6/7/2013"}
valcurrent 的数据类型为 float。但是保存到数据库中的 valcurrent 值不是 3500.0
,而是 3.0
.
问题不在于 CSV,而在于 Ruby 如何将字符串转换为浮点数。
在Ruby中:
"3,500".to_f => 3.0
这就是将 3.0 存储在数据库中的原因。您应该更改 import_csv 方法来处理逗号。
此外,我认为您不应该在创建中执行 row_hash.to_s。这样的 Create 方法接受哈希作为参数。
您可以添加一个自定义转换器来正确处理您的数字列。不确定这是否涵盖了所有可能的格式选项,但它看起来像这样:
创建一个 lambda:
comma_numbers = ->(s) {(s =~ /^\d+,/) ? (s.gsub(',','').to_f) : s}
将其添加到您的转换器中:
CSV::Converters[:comma_numbers] = comma_numbers
新转换器未包含在转换器中::all 所以将其添加为数组:
converters: [:all, :comma_numbers]