为什么CSV :: HeaderConverters在返回非String时停止处理?

jef*_*unt 5 ruby csv

为什么标头转换器的处理在第一个非String标头转换器返回时停止?

细节

:symbol触发内置标头转换器后,不会处理其他转换器.似乎头转换器的处理在第一个转换器停止时返回任何不是a的转换器String(即如果你编写一个返回a Fixnum或其他任何东西的自定义头转换器,则相同的行为).


此代码按预期工作,抛出异常:throw_an_exception

require 'csv'

CSV::HeaderConverters[:throw_an_exception] = lambda do |header|
  raise 'Exception triggered.'
end

csv_str = "Numbers\n" +
          "1\n" +
          "4\n" +
          "7"

puts CSV.parse(
  csv_str,
  {
    headers: true,
    header_converters: [
      :throw_an_exception,
      :symbol
    ]
  }
)
Run Code Online (Sandbox Code Playgroud)

但是,如果切换标头转换器的顺序以使转换:symbol器首先出现,:throw_an_exception则永远不会调用lambda.

...

header_converters: [
  :symbol,
  :throw_an_exception
]

...
Run Code Online (Sandbox Code Playgroud)

jef*_*unt 2

所以我联系了JEG2

我认为转换器应该是一个链中的一系列步骤,其中所有元素都应该经历每个步骤。事实上,这并不是使用 CSV 库的最佳方式,尤其是当您拥有大量数据时。

它应该使用的方式(这是“为什么”问题的答案以及为什么这对性能更好的解释)是让转换器像一系列匹配器一样工作,其中第一个匹配的转换器返回一个非String,这向 CSV 库表明当前值已成功转换。当您这样做时,解析器可以在它是非时立即停止String,并继续处理下一个标头/单元格值。

通过这种方式,您可以在解析 CSV 数据时消除大量开销。您处理的文件越大,消除的开销就越多。

这是我收到的电子邮件回复:

...

转换器基本上是要尝试的转换管道。假设您使用两个转换器,一个用于日期,一个用于数字。如果没有链接线,我们将在每个字段中尝试两者。然而,我们知道一些事情:

  • 未转换的 CSV 字段是String,因为这就是我们读取它的方式
  • 现在非 , 的字段String已被转换,因此我们可以停止搜索匹配的转换器。

鉴于此,如果我们已经有一个对象,优化可以帮助我们的示例跳过检查数字转换器Date

...