【问题标题】:Why do CSV::HeaderConverters stop processing when a non-String is returned?为什么返回非字符串时 CSV::HeaderConverters 会停止处理?
【发布时间】:2016-06-23 19:01:20
【问题描述】:

为什么header converters 的处理会随着从标头转换器返回的第一个非String 而停止?

详情

内置:symbol头转换器触发后,不会再处理其他转换器。似乎头转换器的处理停止,第一个转换器返回不是String 的任何内容(即,如果您编写返回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
    ]
  }
)

但是,如果您切换标头转换器的顺序以使 :symbol 转换器排在第一位,则永远不会调用 :throw_an_exception lambda。

...

header_converters: [
  :symbol,
  :throw_an_exception
]

...

【问题讨论】:

  • 任何不是来自@JEG2 的回答都可能纯属猜测。
  • @FrederickCheung 问题被表述为“为什么标头转换器的处理会随着标头转换器返回的第一个非字符串而停止?”——答案是“因为代码确实显式中断转换器在第一个非字符串上进行链式迭代。”不过,关于“为什么要那样做”的澄清并非来自作者,纯属猜测。

标签: ruby csv


【解决方案1】:

所以我联系了JEG2

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

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

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

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

...

转换器基本上是要尝试的转换管道。假设您正在使用两个转换器,一个用于日期,一个用于数字。如果没有链接线,我们会在每个领域都尝试。但是,我们知道几件事:

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

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

...

【讨论】:

    【解决方案2】:

    不知什么原因CSV#convert_fields函数有一个搞笑

    break unless field.is_a? String # short-circuit pipeline for speed

    输入converters.each。我怀疑我可以提出比猴子修补这个功能更好的建议,但现在原因很清楚了。

    【讨论】:

    • 如果你看高几行,就会注意到这种行为,显然主要是出于速度原因
    • @FrederickCheung 我做到了。这实际上是过早优化的完美示例。标头转换器绝不是 CSV 处理的瓶颈,而这个 break 既具有误导性又有害。
    • 相同的代码被重复用于字段,并且可以想象它可能是那里的瓶颈。
    • 我要么让这个函数接收第三个参数break_on_string,默认为true,或者至少为headers绕过这个break(这已经作为参数传递了。 ) “慢”总是比“出乎意料”好。
    • @mudasobwa - 提交是一个错字更正。当我检查历史时,@jeg2 用基于 FasterCSV 的实现替换旧的 CSV 实现时,break unless ... 行似乎起源于 CSV 的重新实现。我可能需要联系@jeg2 并询问他。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 2013-10-22
    • 2016-10-16
    • 1970-01-01
    相关资源
    最近更新 更多