Разбор файлов XLS и XLSX (MS Excel) с помощью Ruby?
есть ли драгоценные камни, способные анализировать файлы XLS и XLSX? Я нашел электронную таблицу и ParseExcel, но они оба не понимают формат XLSX :( Есть идеи?
спасибо.
10 ответов:
нашел РОО, это может сделать работу-работает для моих требований, читая основную электронную таблицу.
недавно мне нужно было разобрать некоторые файлы Excel с Ruby. Обилие библиотек и опций оказалось запутанным, поэтому я написал блоге об этом.
Вот таблица различных библиотек Ruby и то, что они поддерживают:
если вы заботитесь о производительности, вот как
xlsx
библиотеки сравниваем:у меня есть пример кода для чтения xlsx файлов с каждая поддерживаемая библиотека здесь
вот несколько примеров для чтения
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
РОО
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
библиотека:таблицы
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
на РОО 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. Это быстро. Используется 8,3 секунды на столе 21x11250 xlsx на моем Macbook Air. Получил его для работы на ruby 1.9.3+. Выходной формат для каждой строки-это хэш имени строки и столбца для содержимого ячейки: {"А1"=>"ячейки", "Б1"=>"другой ячейке"} Хэш не гарантирует, что ключи будут находиться в исходном порядке столбцов. https://github.com/pythonicrubyist/creek
тупица-еще один Великий, который использует nokogiri. Это очень быстро. Используемый 6,7 секунды на столе 21x11250 xlsx на моем Macbook Air. Получил его для работы на ruby 2.0.0+. Выходной формат для каждой строки-массив: ["клетка", "другой ячейке"] https://github.com/thirtyseven/dullard
simple_xlsx_reader, который был упомянут, отличный, немного медленный. Используется 91 секунд на столе 21x11250 xlsx на моем Macbook Air. Получил его для работы на ruby 1.9.3+. Выходной формат для каждой строки-массив: ["клетка", "другой клетка"] https://github.com/woahdae/simple_xlsx_reader
еще один интересный-oxcelix. Он использует парсер саксофона ox, который предположительно быстрее, чем DOM и SAX-парсер nokogiri. Он якобы выводит матрицу. Я не мог заставить его работать. Кроме того, были некоторые проблемы зависимости с rubyzip. Не рекомендовал бы его.
В заключение, если используется версия ruby ниже 2.0.0, используйте creek. Если вы используете ruby 2.0.0+, используйте dullard, потому что это быстрее и сохраняет порядок столбцов таблицы.
Если вы ищете более современные библиотеки, взгляните на электронную таблицу:http://spreadsheet.rubyforge.org/GUIDE_txt.html. Я не могу сказать, поддерживает ли он файлы XLSX, но, учитывая, что он активно развивается, я предполагаю, что это так (я не на Windows или с Office, поэтому я не могу тестировать).
На данный момент, это выглядит как РОО - это еще хороший вариант. Он поддерживает XLSX, позволяет (некоторые) итерации, просто используя
times
с доступом к ячейке. Я признаю, что это хотя и не очень красиво.кроме того, RubyXL теперь может дать вам своего рода итерацию, используя их
, как @PanagiotisKanavos упоминалось в комментариях, это имеет несколько основных недостатки:extract_data
метод, который дает вам 2d массив данных,которые могут быть легко повторены.
- Excel должен быть установлен
- новый экземпляр Excel запускается для каждого документа
- потребление памяти и других ресурсов намного больше, чем необходимо для простого управления документами XLSX.
но если вы решите использовать его, вы можете выбрать не отображать Excel, загрузить файл XLSX и получить доступ к нему через него. Я не уверен, что он поддерживает итерацию, однако, я не думаю, что это будет слишком сложно построить вокруг предоставленных методов, так как это полный Microsoft OLE API для Excel. Вот документация:http://support.microsoft.com/kb/222101 Вот жемчужина:http://www.ruby-doc.org/stdlib-1.9.3/libdoc/win32ole/rdoc/WIN32OLE.html
опять же, варианты не выглядят намного лучше, но, боюсь, там больше ничего нет. трудно проанализировать формат файла, который является черным ящиком. И те немногие, кому удалось его сломать, сделали это не так заметно. Гуглить Docs-это закрытый исходный код, а LibreOffice-это тысячи строк harry C++.
The rubyXL gem прекрасно разбирает XLSX файлы.
Я много работал с электронной таблицей и rubyXL за последние пару недель, и я должен сказать, что оба являются отличными инструментами. Однако одна из областей, в которой страдают оба, - это отсутствие примеров фактической реализации чего-либо полезного. В настоящее время я создаю искатель и использую 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"
Я не смог найти удовлетворительный XLSX парсер. RubyXL не выполняет типизацию даты, Roo попытался ввести число в качестве даты, и оба они являются беспорядком как в api, так и в коде.
Итак, я написал simple_xlsx_reader. Вам придется использовать что-то еще для xls, хотя, возможно, это не полный ответ, который вы ищете.
большинство онлайн-примеров, включая веб-сайт автора для электронной таблицы gem, демонстрируют чтение всего содержимого файла Excel в ОЗУ. Это нормально, если ваша электронная таблица мала.
xls = Spreadsheet.open(file_path)
для тех, кто работает с очень большими файлами, лучший способ-это stream-read содержимое файла. Электронная таблица gem поддерживает это,хотя и не очень хорошо документирована в настоящее время (около 3/2015).
Spreadsheet.open(file_path).worksheets.first.rows do |row| # do something with the array of CSV data end
цитировать: https://github.com/zdavatz/spreadsheet
The Удаленная библиотека использует РОО внутренне. Это позволяет легко читать электронные таблицы различных форматов(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"}