【问题标题】:Ruby CSV gem returning Infinity instead of doubleRuby CSV gem 返回 Infinity 而不是 double
【发布时间】:2015-06-02 17:06:28
【问题描述】:

我有一个方法是通过 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”?

【问题讨论】:

  • 当您可以将 CSV 直接复制到 PostgreSQL 中时,您为什么还要使用 Ruby?
  • 我同意使用 Postgres 直接加载 CSV 是正确的方法,但这仍然是一个关于 CSV 库的有趣问题。
  • 因为它不仅仅是我要复制的一个文件。我希望能够每天点击一个按钮,让脚本运行在今天的文件中。

标签: ruby postgresql csv double infinity


【解决方案1】:

首先,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)>]]

【讨论】:

  • 感谢您的回答。我没有意识到 Ruby 的浮点数在 Excel 之前就已经结束了。自定义转换器也非常有用。只是为了补充您的答案,我实际上不想要“2.02E+17”,因为它失去了精确度。 “201505190000000000”将四舍五入为“2.02E+17”,但当输入回 Excel 时,它将是“202000000000000000”。因此最好使用完整的数字并转换为我想要的格式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-16
  • 2017-06-09
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-10
相关资源
最近更新 更多