Ruby CSV - 获取当前行/行号
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12407035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby CSV - get current line/row number
提问by user1513388
I'm trying to work out how to get the current line/row number from Ruby CSV. This is my code:
我正在尝试研究如何从 Ruby CSV 获取当前行/行号。这是我的代码:
options = {:encoding => 'UTF-8', :skip_blanks => true}
CSV.foreach("data.csv", options, ) do |row, i|
puts i
end
But this doesn't seem to work as expected. Is there a way to do this?
但这似乎并没有按预期工作。有没有办法做到这一点?
回答by the Tin Man
Because of changes in CSV in current Rubies, we need to make some changes. See farther down in the answer for the original solution with Ruby prior to 2.6. and the use of with_indexwhich continues to work regardless of the version.
由于当前 Ruby 中 CSV 的更改,我们需要进行一些更改。在 2.6 之前使用 Ruby 的原始解决方案的答案中进一步查看。并且with_index无论版本如何,它的使用都继续有效。
For 2.6+ this'll work:
对于 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
If I read:
如果我读:
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
The code results in this output:
代码导致此输出:
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"]
The change is because we have to get access to the current file handle. Previously we could use the global $., which always had a possibility of failure because globals can get stomped on by other sections of called code. If we have the handle of the file being opened, then we can use linenowithout that concern.
更改是因为我们必须访问当前文件句柄。以前我们可以使用 global $.,它总是有失败的可能性,因为 globals 可能会被其他部分的调用代码踩到。如果我们有正在打开的文件的句柄,那么我们可以lineno不用担心。
$.
$.
Ruby prior to 2.6 would let us do this:
2.6 之前的 Ruby 会让我们这样做:
Ruby has a magic variable $.which is the line number of the current file being read:
Ruby 有一个魔法变量$.,它是当前正在读取的文件的行号:
require 'csv'
CSV.foreach('test.csv') do |csv|
puts $.
end
with the code above, I get:
使用上面的代码,我得到:
1
2
3
4
5
$INPUT_LINE_NUMBER
$INPUT_LINE_NUMBER
$.is used all the time in Perl. In Ruby, it's recommended we use it the following way to avoid the "magical" side of it:
$.在 Perl 中一直使用。在 Ruby 中,建议我们按以下方式使用它以避免其“神奇”的一面:
require 'english'
puts $INPUT_LINE_NUMBER
If it's necessary to deal with embedded line-ends in fields, it's easily handled by a minor modification. Assuming a CSV file "test.csv" which contains a line with an embedded new-line:
如果需要处理字段中嵌入的行尾,只需稍作修改即可轻松处理。假设一个 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
Using Enumerator's with_index(1)makes it easy to keep track of the number of times CSV yields to the block, effectively simulating using $.but honoring CSV's work when reading the extra lines necessary to deal with the line-ends:
使用枚举器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
Which, when run, outputs:
运行时,输出:
$ 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"
回答by Josh Voigts
Here's an alternative solution:
这是一个替代解决方案:
options = {:encoding => 'UTF-8', :skip_blanks => true}
CSV.foreach("data.csv", options).with_index do |row, i|
puts i
end
回答by undur_gongor
Not a clean but a simple solution
不是一个干净的而是一个简单的解决方案
options = {:encoding => 'UTF-8', :skip_blanks => true}
i = 0
CSV.foreach("data.csv", options) do | row |
puts i
i += 1
end
回答by Joshua Pinter
Ruby 2.6+
红宝石 2.6+
Without Headers
没有标题
CSV.foreach( "data.csv", encoding: "UTF-8" ).with_index do |row, row_number|
puts row_number
end
With Headers
带标题
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
In Ruby 2.6, $INPUT_LINE_NUMBERno longer gives you the current line number. What's worse is that it's returning values of 2and 1. I'm not sure what that is supposed to represent but it's certainly not the row number. Since it doesn't raise an exception, it can really bite you if you're not checking that value. I highly recommend you replace all occurrences of $INPUT_LINE_NUMBERin your code to avoid this gotcha.
在 Ruby 2.6 中,$INPUT_LINE_NUMBER不再提供当前行号。更糟糕的是它返回了2and的值1。我不确定那应该代表什么,但肯定不是行号。由于它不会引发异常,如果您不检查该值,它真的会咬您。我强烈建议您替换$INPUT_LINE_NUMBER代码中所有出现的,以避免出现这种问题。

