XLSおよびXLSXファイルを解析できるgemはありますか? SpreadsheetとParseExcelを見つけましたが、どちらもXLSX形式を理解していません。
ちょうど見つけた roo 、それは仕事をするかもしれません-基本的なスプレッドシートを読んで、私の要件に合っています。
最近、いくつかのExcelファイルをRubyで解析する必要がありました。豊富なライブラリとオプションはわかりにくいため、 ブログ投稿 について書きました。
以下に、さまざまなRubyライブラリとそれらがサポートするものの表を示します。
パフォーマンスを重視する場合、xlsx
ライブラリの比較方法は次のとおりです。
サポートされている各ライブラリでxlsxファイルを読み取るサンプルコードがあります here
いくつかの異なるライブラリでxlsx
ファイルを読み取るための例を次に示します。
rubyXL
require 'rubyXL'
workbook = RubyXL::Parser.parse './sample_Excel_files/xlsx_500_rows.xlsx'
worksheets = workbook.worksheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.sheet_name}"
num_rows = 0
worksheet.each do |row|
row_cells = row.cells.map{ |cell| cell.value }
num_rows += 1
end
puts "Read #{num_rows} rows"
end
roo
require 'roo'
workbook = Roo::Spreadsheet.open './sample_Excel_files/xlsx_500_rows.xlsx'
worksheets = workbook.sheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet}"
num_rows = 0
workbook.sheet(worksheet).each_row_streaming do |row|
row_cells = row.map { |cell| cell.value }
num_rows += 1
end
puts "Read #{num_rows} rows"
end
creek
require 'creek'
workbook = Creek::Book.new './sample_Excel_files/xlsx_500_rows.xlsx'
worksheets = workbook.sheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.name}"
num_rows = 0
worksheet.rows.each do |row|
row_cells = row.values
num_rows += 1
end
puts "Read #{num_rows} rows"
end
simple_xlsx_reader
require 'simple_xlsx_reader'
workbook = SimpleXlsxReader.open './sample_Excel_files/xlsx_500000_rows.xlsx'
worksheets = workbook.sheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.name}"
num_rows = 0
worksheet.rows.each do |row|
row_cells = row
num_rows += 1
end
puts "Read #{num_rows} rows"
end
以下は、xls
ライブラリを使用してレガシーspreadsheet
ファイルを読み取る例です。
スプレッドシート
require 'spreadsheet'
# Note: spreadsheet only supports .xls files (not .xlsx)
workbook = Spreadsheet.open './sample_Excel_files/xls_500_rows.xls'
worksheets = workbook.worksheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.name}"
num_rows = 0
worksheet.rows.each do |row|
row_cells = row.to_a.map{ |v| v.methods.include?(:value) ? v.value : v }
num_rows += 1
end
puts "Read #{num_rows} rows"
end
roo gemはExcel(.xlsおよび.xlsx)に最適であり、積極的に開発されています。
私は構文が素晴らしいものでもRubyのようなものでもないことに同意します。ただし、次のような方法で簡単に実現できます。
class Spreadsheet
def initialize(file_path)
@xls = Roo::Spreadsheet.open(file_path)
end
def each_sheet
@xls.sheets.each do |sheet|
@xls.default_sheet = sheet
yield sheet
end
end
def each_row
0.upto(@xls.last_row) do |index|
yield @xls.row(index)
end
end
def each_column
0.upto(@xls.last_column) do |index|
yield @xls.column(index)
end
end
end
ノコギリを使用したクリークを使用しています。速いです。 Macbook Airの21x11250 xlsxテーブルで8.3秒使用しました。動作するようになったRuby 1.9.3+。各行の出力形式は、セルの内容に対する行と列の名前のハッシュです:{"A1" => "a cell"、 " B1 "=>" another cell "}ハッシュは、キーが元の列の順序になることを保証しません。 https://github.com/pythonicrubyist/creek
dullardは、のこぎりを使用するもう1つのすばらしいツールです。超高速です。 Macbook Airの21x11250 xlsxテーブルで6.7秒使用しました。 Ruby 2.0.0+。各行の出力フォーマットは配列です:["a cell"、 "another cell"] https:// github .com/thirtyseven/dullard
前述のsimple_xlsx_readerは素晴らしいですが、少し遅いです。 Macbook Airの21x11250 xlsxテーブルで91秒使用しました。 Ruby 1.9.3+。各行の出力形式は配列です:["a cell"、 "another cell"] https:// github .com/woahdae/simple_xlsx_reader
もう1つの興味深いものはoxcelixです。これは、nokogiriのDOMおよびSAXパーサーよりも高速であると思われるoxのSAXパーサーを使用します。おそらくマトリックスを出力します。私はそれを動作させることができませんでした。また、rubyzipにはいくつかの依存関係の問題がありました。お勧めしません。
結論として、クリークは良い選択のようです。他の投稿では、simple_xlsx_parserが同様のパフォーマンスを持っているため、推奨しています。
推奨されているようにダラードを削除しました。古いため、エラーが発生したり、問題が発生したりします。
最新のライブラリを探している場合は、スプレッドシートをご覧ください: http://spreadsheet.rubyforge.org/GUIDE_txt.html 。 XLSXファイルをサポートしているかどうかはわかりませんが、積極的に開発されていることを考えると、サポートしていると思います(WindowsやOfficeを使用していないため、テストできません)。
この時点では、 roo が適切なオプションであるように見えます。 XLSXをサポートし、セルアクセスでtimes
を使用するだけで(一部)の反復が可能です。私は認めますが、それはきれいではありません。
また、RubyXLは、extract_data
メソッド。データの2次元配列を提供し、簡単に反復処理できます。
あるいは、WindowsでXLSXファイルを使用する場合は、RubyのWin32OLEライブラリを使用して、WordやExcelが提供するようなOLEオブジェクトとのインターフェースを可能にします。ただし、、@ PanagiotisKanavosがコメントで言及したように、これにはいくつかの大きな欠点があります:
ただし、使用することを選択した場合は、Excelを表示せずにXLSXファイルをロードし、そのファイルからアクセスできます。反復をサポートしているかどうかはわかりませんが、完全なMicrosoft OLE Excel用APIであるため、提供されたメソッドを構築するのはそれほど難しくないと思います。ドキュメント: http://support.Microsoft.com/kb/222101 ここに宝石があります: http://www.Ruby-doc.org/stdlib-1.9.3/libdoc /win32ole/rdoc/WIN32OLE.html
繰り返しになりますが、オプションはそれほど良く見えませんが、他にそれほど多くはありません、私は恐れています。ブラックボックスのファイル形式を解析するのは困難です。そして、それを破ることができた少数の人は、目に見えてそれをしませんでした。 Google Docsはクローズドソースであり、LibreOfficeは何千行ものハリーC++です。
私はこの数週間、SpreadsheetとrubyXLの両方を頻繁に使用してきましたが、どちらも素晴らしいツールだと言わざるを得ません。ただし、両方が苦しむ1つの領域は、有用なものを実際に実装する例の欠如です。現在、クローラーを作成しており、rubyXLを使用してxlsxファイルとスプレッドシートを解析し、xlsを探しています。以下のコードが役に立つ例となり、これらのツールがどれほど効果的であるかを示すことを願っています。
require 'find'
require 'rubyXL'
count = 0
Find.find('/Users/Anconia/crawler/') do |file| # begin iteration of each file of a specified directory
if file =~ /\b.xlsx$\b/ # check if file is xlsx format
workbook = RubyXL::Parser.parse(file).worksheets # creates an object containing all worksheets of an Excel workbook
workbook.each do |worksheet| # begin iteration over each worksheet
data = worksheet.extract_data.to_s # extract data of a given worksheet - must be converted to a string in order to match a regex
if data =~ /regex/
puts file
count += 1
end
end
end
end
puts "#{count} files were found"
require 'find'
require 'spreadsheet'
Spreadsheet.client_encoding = 'UTF-8'
count = 0
Find.find('/Users/Anconia/crawler/') do |file| # begin iteration of each file of a specified directory
if file =~ /\b.xls$\b/ # check if a given file is xls format
workbook = Spreadsheet.open(file).worksheets # creates an object containing all worksheets of an Excel workbook
workbook.each do |worksheet| # begin iteration over each worksheet
worksheet.each do |row| # begin iteration over each row of a worksheet
if row.to_s =~ /regex/ # rows must be converted to strings in order to match the regex
puts file
count += 1
end
end
end
end
end
puts "#{count} files were found"
rubyXL gemはXLSXファイルを美しく解析します。
満足できるxlsxパーサーが見つかりませんでした。 RubyXLは日付型キャストを行わず、Rooは数値を日付として型キャストしようとしましたが、どちらもAPIとコードの両方で混乱しています。
そこで、私は simple_xlsx_reader を書きました。ただし、xlsには他の何かを使用する必要があるため、探している完全な答えではない可能性があります。
Spreadsheet gemの著者のWebサイトを含むほとんどのオンライン例では、Excelファイルのコンテンツ全体をRAMに読み込む方法を示しています。スプレッドシートが小さい場合は問題ありません。
xls = Spreadsheet.open(file_path)
非常に大きなファイルを扱う人にとって、より良い方法はファイルの内容をstream-readにすることです。 Spreadsheet gemは、これをサポートしていますが、現時点では文書化されていません(2015年3月頃)。
Spreadsheet.open(file_path).worksheets.first.rows do |row|
# do something with the array of CSV data
end
RemoteTableライブラリ は、内部的に roo を使用します。さまざまな形式のスプレッドシート(XLS、XLSX、CSVなど、リモート、場合によってはZip、gzなどに格納されている場合)を簡単に読み取ることができます。
require 'remote_table'
r = RemoteTable.new 'http://www.fueleconomy.gov/FEG/epadata/02data.Zip', :filename => 'guide_jan28.xls'
r.each do |row|
puts row.inspect
end
出力:
{"Class"=>"TWO SEATERS", "Manufacturer"=>"ACURA", "carline name"=>"NSX", "displ"=>"3.0", "cyl"=>"6.0", "trans"=>"Auto(S4)", "drv"=>"R", "bidx"=>"60.0", "cty"=>"17.0", "hwy"=>"24.0", "cmb"=>"20.0", "ucty"=>"19.1342", "uhwy"=>"30.2", "ucmb"=>"22.9121", "fl"=>"P", "G"=>"", "T"=>"", "S"=>"", "2pv"=>"", "2lv"=>"", "4pv"=>"", "4lv"=>"", "hpv"=>"", "hlv"=>"", "fcost"=>"1238.0", "eng dscr"=>"DOHC-VTEC", "trans dscr"=>"2MODE", "vpc"=>"4.0", "cls"=>"1.0"}
{"Class"=>"TWO SEATERS", "Manufacturer"=>"ACURA", "carline name"=>"NSX", "displ"=>"3.2", "cyl"=>"6.0", "trans"=>"Manual(M6)", "drv"=>"R", "bidx"=>"65.0", "cty"=>"17.0", "hwy"=>"24.0", "cmb"=>"19.0", "ucty"=>"18.7", "uhwy"=>"30.4", "ucmb"=>"22.6171", "fl"=>"P", "G"=>"", "T"=>"", "S"=>"", "2pv"=>"", "2lv"=>"", "4pv"=>"", "4lv"=>"", "hpv"=>"", "hlv"=>"", "fcost"=>"1302.0", "eng dscr"=>"DOHC-VTEC", "trans dscr"=>"", "vpc"=>"4.0", "cls"=>"1.0"}
{"Class"=>"TWO SEATERS", "Manufacturer"=>"ASTON MARTIN", "carline name"=>"ASTON MARTIN VANQUISH", "displ"=>"5.9", "cyl"=>"12.0", "trans"=>"Auto(S6)", "drv"=>"R", "bidx"=>"1.0", "cty"=>"12.0", "hwy"=>"19.0", "cmb"=>"14.0", "ucty"=>"13.55", "uhwy"=>"24.7", "ucmb"=>"17.015", "fl"=>"P", "G"=>"G", "T"=>"", "S"=>"", "2pv"=>"", "2lv"=>"", "4pv"=>"", "4lv"=>"", "hpv"=>"", "hlv"=>"", "fcost"=>"1651.0", "eng dscr"=>"GUZZLER", "trans dscr"=>"CLKUP", "vpc"=>"4.0", "cls"=>"1.0"}