Ruby CSV - 获取当前行/行号

时间:2012-09-13 13:08:56

标签: ruby csv

我正在尝试弄清楚如何从Ruby CSV获取当前行/行号。这是我的代码:

options = {:encoding => 'UTF-8', :skip_blanks => true}
CSV.foreach("data.csv", options, ) do |row, i|
   puts i
end

但这似乎没有按预期工作。有没有办法做到这一点?

4 个答案:

答案 0 :(得分:119)

由于当前Rubies中CSV的变化,我们需要进行一些更改。请参阅2.6之前的Ruby原始解决方案的答案。以及with_index的使用,无论版本如何,它都会继续有效。

对于2.6+这个工作:

require 'csv'

puts RUBY_VERSION

csv_file = CSV.open('test.csv')
csv_file.each do |csv_row|
  puts '%i %s' % [csv_file.lineno, csv_row]
end
csv_file.close

如果我读到:

Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""","",5000.00
1996,Jeep,Grand Cherokee,"MUST SELL!\nair, moon roof, loaded",4799.00

代码导致此输出:

2.6.3
1 ["Year", "Make", "Model", "Description", "Price"]
2 ["1997", "Ford", "E350", "ac, abs, moon", "3000.00"]
3 ["1999", "Chevy", "Venture \"Extended Edition\"", "", "4900.00"]
4 ["1999", "Chevy", "Venture \"Extended Edition, Very Large\"", "", "5000.00"]
5 ["1996", "Jeep", "Grand Cherokee", "MUST SELL!\\nair, moon roof, loaded", "4799.00"]

更改是因为我们必须访问当前文件句柄。以前我们可以使用全局$.,它总是有可能失败,因为全局变量可以被调用代码的其他部分踩踏。如果我们打开了文件的句柄,那么我们可以使用lineno而无需担心。


$.

2.6之前的

Ruby会让我们这样做:

Ruby有一个magic variable $.,它是当前正在读取的文件的行号:

require 'csv'

CSV.foreach('test.csv') do |csv|
  puts $.
end

使用上面的代码,我得到:

1
2
3
4
5

$INPUT_LINE_NUMBER

在Perl中始终使用

$.。在Ruby中,建议我们使用以下方法来避免它的“神奇”一面:

require 'english'

puts $INPUT_LINE_NUMBER

如果有必要在字段中处理嵌入式行尾,则可以通过微小修改轻松处理。假设CSV文件“test.csv”包含带有嵌入换行符的行:

Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799.00
1999,Chevy,"Venture ""Extended Edition, Very Large""","",5000.00

with_index

使用枚举器的with_index(1)可以轻松跟踪CSV向块产生的次数,有效地使用$.进行模拟,但在阅读处理线路所需的额外行时遵守CSV的工作-ends:

require 'csv'

CSV.foreach('test.csv', headers: true).with_index(1) do |row, ln|
  puts '%-3d %-5s %-26s %s' % [ln, *row.values_at('Make', 'Model', 'Description')]
end

运行时输出:

$ ruby test.rb
1   Ford  E350                       ac, abs, moon
2   Chevy Venture "Extended Edition"
3   Jeep  Grand Cherokee             MUST SELL!
air, moon roof, loaded
4   Chevy Venture "Extended Edition, Very Large"

答案 1 :(得分:30)

这是另一种解决方案:

options = {:encoding => 'UTF-8', :skip_blanks => true}

CSV.foreach("data.csv", options).with_index do |row, i|
   puts i
end

答案 2 :(得分:5)

不是一个干净但简单的解决方案

options = {:encoding => 'UTF-8', :skip_blanks => true}
i = 0
CSV.foreach("data.csv", options) do | row |
  puts i
  i += 1
end

答案 3 :(得分:1)

Ruby 2.6 +

没有标题

CSV.foreach( "data.csv", encoding: "UTF-8" ).with_index do |row, row_number|
  puts row_number
end

带有标题

CSV.foreach( "data.csv", encoding: "UTF-8", headers: true ).with_index( 2 ) do |row, row_number|
  puts row_number # Starts at row 2, which is the first row after the header row.
end

在Ruby 2.6中,$INPUT_LINE_NUMBER不再为您提供当前行号。更糟糕的是,它返回的值为21。我不确定应该代表什么,但肯定不是行号。由于它不会引发异常,因此如果您不检查该值,它确实会咬住您。 我强烈建议您替换代码中所有出现的$INPUT_LINE_NUMBER,以避免出现此问题。