[英]Ruby CSV - get current line/row number
我正在尝试研究如何从 Ruby CSV 获取当前行/行号。 这是我的代码:
options = {:encoding => 'UTF-8', :skip_blanks => true}
CSV.foreach("data.csv", options, ) do |row, i|
puts i
end
但这似乎并没有按预期工作。 有没有办法做到这一点?
由于当前 Ruby 中 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 有一个神奇的变量$.
这是正在读取的当前文件的行号:
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
使用 Enumerator 的with_index(1)
可以轻松跟踪 CSV 生成块的次数,有效地模拟使用$.
但是在阅读处理行尾所需的额外行时尊重 CSV 的工作:
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"
这是一个替代解决方案:
options = {:encoding => 'UTF-8', :skip_blanks => true}
CSV.foreach("data.csv", options).with_index do |row, i|
puts i
end
不是一个干净的而是一个简单的解决方案
options = {:encoding => 'UTF-8', :skip_blanks => true}
i = 0
CSV.foreach("data.csv", options) do | row |
puts i
i += 1
end
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
不再提供当前行号。 更糟糕的是,它返回2
和1
值。 我不确定那应该代表什么,但肯定不是行号。 由于它不会引发异常,如果您不检查该值,它真的会咬您。 我强烈建议您替换代码中所有出现的$INPUT_LINE_NUMBER
以避免出现这种问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.