require 'rubygems' require 'parseexcel' class Excel < Openoffice def initialize(filename) if filename[-4..-1] != ".xls" warn "are you sure, this is an excel file?" end @filename = filename @workbook = Spreadsheet::ParseExcel.parse(filename) @default_sheet = nil @first_row = @last_row = @first_column = @last_column = nil end def sheets #if DateTime.now < Date.new(2007,6,10) # return ["Tabelle1", "Name of Sheet 2", "Sheet3"] #else result = [] 0.upto(@workbook.sheet_count - 1) do |i| # TODO: is there a better way to do conversion? result << Iconv.new('utf-8','unicode').iconv( @workbook.worksheet(i).name ) end return result #end end # sets the working sheet (1,2,3,..) #-- # im Excel-Bereich muesste man wahrscheinlich intern mit Nummern arbeiten # von aussen arbeite ich mit (1,2,3... intern wird Index 0,1,2,... # verwendet. def default_sheet=(n) if DateTime.now < Date.new(2007,7,19) unless n.kind_of?(Fixnum) fail ArgumentError.new("Number expected") end @default_sheet = n-1 else # parseexcel supports now the name of a sheet @default_sheet = n end @first_row = @last_row = @first_column = @last_column = nil @cells_read = false end # returns the content of a cell. The upper left corner is (1,1) or ('A',1) def cell(row,col) row,col = normalize(row,col) worksheet = @workbook.worksheet(sheet_no(@default_sheet)) skip = 0 line = 1 worksheet.each(skip) { |row_par| if line == row if row_par == nil return nil end cell = row_par.at(col-1) return nil unless cell case cell.type when :numeric then return cell.to_f when :text then return cell.to_s('utf-8') when :date then return cell.date else return cell.to_s('utf-8') end end line += 1 } end # returns the type of a cell: "float", "string", "date" def celltype(row,col) row,col = normalize(row,col) default_sheet_check worksheet = @workbook.worksheet(sheet_no(@default_sheet)) skip = 0 line = 1 worksheet.each(skip) { |row_par| if line == row cell = row_par.at(col-1) return nil unless cell case cell.type when :numeric then return :float when :text then return :string when :date then return :date else return cell.type.to_sym end end line += 1 } end # return this row a an array off cells def row(rownumber) default_sheet_check worksheet = @workbook.worksheet(sheet_no(@default_sheet)) therow = worksheet.row(rownumber-1) result = [] therow.each {|cell| case cell.type when :numeric then result << cell.to_i when :text then result << cell.to_s('utf-8') when :date then result << cell.date else #p cell.type return result << cell.to_s('utf-8') end #result << cell.value } return result end # returns the first non empty column def first_column return @first_column if @first_column fr, lr, fc, lc = get_firsts_lasts fc end # returns the last non empty column def last_column return @last_column if @last_column fr, lr, fc, lc = get_firsts_lasts lc end # returns the first non empty row def first_row return @first_row if @first_row fr, lr, fc, lc = get_firsts_lasts fr end # returns the last non empty row def last_row return @last_row if @last_row fr, lr, fc, lc = get_firsts_lasts lr end # true if a cell is empty def empty?(row, col) row,col = normalize(row,col) return true if row < first_row || row > last_row || col < first_column || col > last_column return true unless cell(row, col) return true if celltype(row, col) == "string" && cell(row, col) == "" false end private # check if default_sheet was set def default_sheet_check raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil end # determine the first and last boundaries def get_firsts_lasts fr = fc = 999_999 lr = lc = -999_999 worksheet = @workbook.worksheet(sheet_no(@default_sheet)) skip = 0 line = 1 worksheet.each(skip) { |row_par| if row_par row_par.each_with_index {|cell,i| # nicht beruecksichtigen, wenn nil und vorher noch nichts war # p cell if !cell # nix else fc = [fc, i+1].min lc = [lc, i+1].max fr = [fr, line].min lr = [lr, line].max end } else #??? end line += 1 } @first_row = fr @last_row = lr @first_column = fc @last_column = lc return fr, lr, fc, lc end # converts name of a sheet to index (0,1,2,..) def sheet_no(name) return name-1 if name.kind_of?(Fixnum) 0.upto(@workbook.sheet_count - 1) do |i| # TODO: is there a better way to do conversion? return i if name == Iconv.new('utf-8','unicode').iconv( @workbook.worksheet(i).name ) end raise StandardError, "sheet '#{name}' not found" end end