【问题标题】:Ruby CSV - Retrieve original, raw line with each row parsed?Ruby CSV - 检索每行解析的原始原始行?
【发布时间】:2020-09-08 07:35:49
【问题描述】:

TL;DR:如何在解析 csv 文件时获取原始输入行(不是行号)?

我正在使用 Ruby 的 CSV 类解析一个分隔文件。除了从该行解析的字段外,我还想从文件中检索每一行的原始行。

这是我现在拥有的:

    CSV.foreach(input_file, csv_params) do |row|
      add_uploaded_user(row)
    end

效果很好。每个文件都被正确解析,并且 add_uploaded_user 做它应该做的事情。

我们从一个客户那里得到了一些不寻常的文件,其中包含意外的用户名。该文件是有效的 csv 并且可以正确解析。他们声称我们正在弄乱他们的记录,因此我们希望在解析文件之前从文件中捕获每个原始行。我们已经保存了整个 CSV 文件,但是当我们收到投诉时,手动拉文件并查找源记录很不方便。我们想给他们一个工具,这样他们就可以准确地验证他们发送给我们的内容。此外,我们无法从该文件中透露相关用户的其他记录,因此我们无法共享整个文件。

因此,我们希望使用我们从文件创建的每个解析记录来捕获原始输入行。像这样的:

    CSV.foreach(input_file, csv_params) do |row|
      add_uploaded_user(row, row.raw_line)
    end

...raw_line 是 CSV 中的一些方法/属性/帮助器,它显示了刚刚解析的行。

我浏览了 CSV 文档,找到了https://ruby-doc.org/stdlib-2.6.1/libdoc/csv/rdoc/CSV.html#method-i-line

  • line() - 从此文件读取的最后一行。

但我不知道如何拨打line()。我尝试了几次调用,结果都差不多,NoMethodError: undefined method 'line' for CSV:Class

irb(main):022:0> CSV.line
NoMethodError: undefined method 'line' for CSV:Class


irb(main):049:0* csv = CSV.new("a,b,c\n1,2,3\n")
=> <#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
irb(main):050:0> csv.each do |row|
irb(main):051:1*   puts row
irb(main):052:1>   puts csv.line
irb(main):053:1> end
a
b
c
NoMethodError: undefined method 'line' for #<CSV:0x00007feeb25de3c0>
  from (irb):52:in 'block in irb_binding'
  from (irb):50
irb(main):054:0>

还有一个更简单的例子,读取一个实际的文件:

irb(main):055:0> csv = CSV.new(File.open('3_licenses.csv'))
=> <#CSV io_type:File io_path:"3_licenses.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\r\n" quote_char:"\"">
irb(main):062:0> csv.shift
=> ["first_name", "last_name", "license_number"]
irb(main):063:0> csv.shift
=> ["David ", "Hempy", "1001"]
irb(main):064:0> csv.line
NoMethodError: undefined method 'line' for #<CSV:0x00007feeb2591020>
  from (irb):64
irb(main):065:0> csv.shift
=> ["Santa", "Claus", "np.1"]

更新:

我正在阅读的文档是针对 2.6 的。我正在运行 ruby​​ 2.4.5,但看起来它当时也在那里:https://ruby-doc.com/stdlib-2.4.5/libdoc/csv/rdoc/CSV.html#method-i-line。有趣的是,.line 并没有在https://docs.ruby-lang.org/en/2.4.0/CSV.html 中提及 嗯....

另外,我不需要行号——我需要输入文件中的原始行。

此时,我已经准备好自己阅读这些行,然后为每一行分别调用 CSV。这肯定会起作用并让我控制......但我仍然很困惑为什么我不能调用文档中描述的.line() 方法。如果有人能明白为什么我会得到“未定义的方法'line'”,我一定会很感激的。

【问题讨论】:

  • 查看 CSV 的 documentation。它有许多易于理解的示例,涵盖了许多不同的用例。
  • 你的问题问得不好。请参阅“How to Ask”、“Stack Overflow question checklist”和“MCVE”及其所有链接页面。我们需要一个 CSV 输入的小示例、重写以访问该输入的代码以及您的预期输出。我们不知道add_uploaded_user 是什么,我们无法运行您的代码,也无法在没有输入或您预期的输出的情况下判断什么是有效的或满足您的需求。
  • 我想我的意图并不清楚......文件的解析工作正常,并且 add_upload_user() 是无关紧要的......让我们假装我称之为“foobar()”而不是“添加上传用户”。我的问题的重点是,除了已解析的字段数组之外,是否可以看到原始输入行。我们希望这样,当客户在几个月后打电话给我们时,我们可以向他们显示他们在 csv 文件中发送给我们的确切来源,仅针对那条记录。 (我将编辑问题以使其更清楚。)

标签: ruby csv


【解决方案1】:

当文档提到 CSV#line 时,它们意味着您必须在 CSV 实例上调用它:

require 'csv'

csv = CSV.new(File.open('example.csv'))

csv.each do |row|
  p csv.line
end

【讨论】:

  • 谢谢,塔德曼。我复制了你的代码,并尝试了它的一些变体,但我仍然得到,`NoMethodError: undefined method line' for #&lt;CSV:0x00007feeb2591020&gt;。请参阅我刚刚添加到问题中的最后一个代码块以获取示例。欢迎任何其他帮助。
  • 这在 Ruby 2.7 中有效。如果你想使用它,你可能需要升级,或者找到 2.4 的 CSV gem。
猜你喜欢
  • 2023-04-07
  • 2021-06-09
  • 2010-12-19
  • 2019-11-03
  • 1970-01-01
  • 2020-08-08
  • 2012-10-26
  • 2011-06-08
  • 2011-02-18
相关资源
最近更新 更多