[英]Parsing XLS and XLSX (MS Excel) files with Ruby?
有沒有可以解析XLS和XLSX文件的gem? 我找到了Spreadsheet和ParseExcel,但是它們都不了解XLSX格式。
我最近需要用Ruby解析一些Excel文件。 原來,豐富的庫和選項令人困惑,所以我寫了一篇關於它的博客文章 。
這是不同的Ruby庫及其支持的表:
我的示例代碼讀取XLSX與每個支持庫文件在這里
以下是一些使用一些不同庫讀取xlsx
文件的示例:
紅寶石XL
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
袋鼠
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
溪
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
這是使用spreadsheet
庫讀取舊版xls
文件的示例:
電子表格
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可能會勝任工作-可以滿足我的要求,閱讀基本的電子表格。
roo gem對於Excel(.xls和.xlsx)非常有用,並且正在積極開發中。
我同意語法不太好,也不像紅寶石一樣。 但這可以通過以下方式輕松實現:
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
我正在使用使用nokogiri的小河。 很快 在Macbook Air的21x11250 xlsx桌上使用了8.3秒。 可以在Ruby 1.9.3+上運行。 每行的輸出格式是行和列名稱對單元格內容的哈希:{“ A1” =>“ a cell”,“ B1” =>“另一個單元格”}哈希不能保證鍵將位於原始列順序。 https://github.com/pythonicrubyist/creek
呆板是另一個使用nokogiri的偉大工具。 超級快。 在Macbook Air的21x11250 xlsx桌上使用了6.7秒。 可以在ruby 2.0.0+上運行。 每行的輸出格式是一個數組:[“一個單元格”,“另一個單元格”] https://github.com/thirtyseven/dullard
已經提到過的simple_xlsx_reader很棒,有點慢。 在Macbook Air的21x11250 xlsx桌上使用了91秒。 可以在Ruby 1.9.3+上運行。 每行的輸出格式是一個數組:[“一個單元格”,“另一個單元格”] https://github.com/woahdae/simple_xlsx_reader
另一個有趣的是oxcelix。 它使用ox的SAX解析器,該解析器比nokogiri的DOM和SAX解析器都快。 據推測,它輸出一個矩陣。 我無法正常工作。 此外,rubyzip還存在一些依賴項問題。 不會推薦它。
總之,小溪似乎是一個不錯的選擇。 其他帖子推薦simple_xlsx_parser,因為它具有類似的性能。
根據建議,刪除了過時的文字,因為它過時了,人們對此有錯誤/有問題。
如果您正在尋找更現代的庫,請查看Spreadsheet: http : //spreadsheet.rubyforge.org/GUIDE_txt.html 。 我無法確定它是否支持XLSX文件,但是考慮到它是積極開發的,我猜測它確實支持(我不在Windows或Office上,因此無法測試)。
在這一點上, roo似乎又是一個不錯的選擇。 它支持XLSX,僅通過使用單元訪問times
就可以進行(某些)迭代。 我承認,雖然不是很漂亮。
此外,RubyXL現在可以使用其extract_data
方法為您提供某種迭代,該方法可以為您提供2d數據數組,可以輕松地對其進行迭代。
另外,如果您嘗試在Windows上使用XLSX文件,則可以使用Ruby的Win32OLE庫,該庫允許您與OLE對象(如Word和Excel提供的對象)進行接口。 但是 ,正如@PanagiotisKanavos在評論中提到的那樣,它有一些主要缺點:
但是,如果選擇使用它,則可以選擇不顯示Excel,加載XLSX文件並通過它訪問它。 我不確定它是否支持迭代,但是,我認為圍繞提供的方法進行構建不會太困難,因為它是用於Excel的完整Microsoft OLE API。 這是文檔: http : //support.microsoft.com/kb/222101這是瑰寶: http : //www.ruby-doc.org/stdlib-1.9.3/libdoc/win32ole/rdoc/WIN32OLE.html
同樣,這些選項看起來並沒有好得多,但是恐怕沒有太多其他選擇了。 很難解析是黑匣子的文件格式。 那些設法打破它的人很少能做到這一點。 Google文檔是封閉源代碼,而LibreOffice是數千行Carry C ++。
在過去的兩周中,我一直在與Spreadsheet和rubyXL進行大量的工作,我必須說兩者都是很好的工具。 但是,兩者都遭受的一個方面是缺少實際實施任何有用的示例。 目前,我正在構建一個搜尋器,並使用rubyXL解析任何xls的xlsx文件和Spreadsheet。 我希望下面的代碼可以作為一個有用的示例,並說明這些工具的有效性。
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上的網站在內的大多數在線示例都演示了將Excel文件的全部內容讀入RAM的過程。 如果您的電子表格很小,那很好。
xls = Spreadsheet.open(file_path)
對於使用超大文件的任何人,更好的方法是流式讀取文件的內容。 Spreadsheet gem對此提供了支持-盡管目前(在2015年3月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"}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.