簡體   English   中英

Ruby CSV - 獲取當前行/行號

[英]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

紅寶石 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以避免出現這種問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM