web-dev-qa-db-ja.com

Ruby CSV-現在の行/行番号を取得

Ruby CSV。これは私のコードです。

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

しかし、これは期待どおりに機能しないようです。これを行う方法はありますか?

49
user1513388

現在のルビーではCSVが変更されているため、いくつかの変更を加える必要があります。 Ruby 2.6より前の元のソリューションと、バージョンに関係なく機能し続ける_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"
_
121
the Tin Man

代替ソリューションは次のとおりです。

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

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

クリーンではなく、シンプルなソリューション

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