RubyCSVから現在の行/行番号を取得する方法を見つけようとしています。これは私のコードです:
options = {:encoding => 'UTF-8', :skip_blanks => true}
CSV.foreach("data.csv", options, ) do |row, i|
puts i
end
しかし、これは期待どおりに機能していないようです。これを行う方法はありますか?
現在の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には、現在読み取られているファイルの行番号であるマジック変数があります。$.
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の作業を効果的にシミュレートしますが、それを尊重します。
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