Ruby CSV gem 返回 Infinity 而不是 double

Ruby CSV gem returning Infinity instead of double

我有一个方法可以处理 CSV 文件并上传到 Postgres。

CSV.foreach(path, converters: :all)

遇到数字比如“2.02E+17”就上传“2.0150519e+17”,遇到“20150515E000590”就上传"Infinity".

如果我设置

CSV.foreach(path)

遇到“2.02E+17”时,它正在将“20150519E000010”和“20150515E000590”上传为“20150515E000590”。

我想上传 Excel 中显示的内容。所以在“2.02E+17”的情况下我想上传“2.02E+17”,但在“20150515E000590”的情况下我想上传“20150515E000590”而不是"Infinity"。我想我的问题是如何让 CSV 不使用 "Infinity"?

覆盖“20150515E000590”

首先,Postgres 可以在没有 Ruby 帮助的情况下处理加载 CSV。至于你的问题...


CSV 不定义数据类型,因此每当您将 CSV 数据读入需要数据类型(如 Excel 或 Ruby)的内容时,程序都必须猜测。

当Excel看到20150519E000010时,猜测这是科学记数法20150519e10即20150519×1010。 Excel 区分电子表格中的基础 数据 显示 的方式,因此在本例中它选择了显示该数字的更短方式:2.02E+17。因此,即使 Excel 向您显示 2.02E+17,文件中的 实际数据 20150519E000010.

当您读取 Ruby 中的 CSV 并告诉它转换为 Ruby 的数据类型时,它会做出相同的猜测(即科学记数法),但您会得到不同的显示:2.0150519e+17。这应该是预料之中的,因为 2.02E+17Excel 缩短显示数字的方式 。 Ruby 的数据类型不符合 Excel。这也解释了为什么20150515E00059变成了Infinity。 20150515×1059 对于 Ruby 的浮点数据类型来说太大了,所以 Ruby 将其转换为最大可能的浮点数:Infinity.

但是,我强烈怀疑Excel和Ruby都是错误的。当我看到 20150515E000059 时,它看起来像 2015-05-15 00:00:59。这不是科学计数法中的数字,而是时间戳!您可以定义一个自定义转换器来处理格式:

CSV::Converters[:mytime] = lambda do |s|
  DateTime.parse(s.tr(?E, ?T)) rescue s
end

CSV.parse("20150515000019", converters: :mytime)
# [[#<DateTime: 2015-05-15T00:00:19+00:00 ((2457158j,19s,0n),+0s,2299161j)>]]