こんにちは。学生アルバイトの橋本です。今回はrubyXLというgemを使ったエクセルファイルの読み込みについて紹介します。

rubyXLの使い方

rubyXLでは基本的に以下のようにしてエクセルファイルを読み込みます。

require "rubyXL"

#エクセル読み込み
excel = RubyXL::Parser.parse('sample.xlsx')

#シート取得
sheet = excel[0]

#行取得
row = sheet[0]

#セル情報取得
cell = row[0]

#値
cell.value

rubyXlがrooの代用として必要な時

rubyで既存のエクセルファイルを読み込みたいとき、いくつか方法はありますが、多くの人が真っ先に考える方法はrooではないでしょうか。 実際に、私はエクセルファイルを読み込みだけしたい時は、読み込み専用であるrooを使うようにしています。 そのため、わざわざrubyXLを使うことはありませんでした。 しかし、ある時rooでパースすると特定のセルが出力できないファイルに出会ってしまいました。そのセルを出力しようとするとこのようなエラーが出てしまいました。

require "roo"
excel = Roo::Excelx.new('sample.xlsx',:expand_merged_ranges => true)
excel_arr = excel.sheet(0)
p excel_arr.cell(14,14)
#=>invalid value for Integer(): "90," (ArgumentError)

試しにこのエクセルファイルを開こうとすると、

‘sample.xlsx’ の一部の内容に問題が見つかりました。可能な限り内容を回復しますか? ブックの発行元が信頼できる場合は、[はい] をクリックしてください。

という表示が出ました。このエクセルファイルに問題があるようです。 しかし、rubyXLを使って同じファイルの同じセルを出力しようとすると

require "rubyXL"

excel = RubyXL::Parser.parse('sample.xlsx')
p excel.worksheets[0][13][13].value
#=>"90,"

どうやらうまく出力できました。rooでできなくてもrubyXLでできることがあるようです。

結合セルについて

rubyXLはおおよそrooと同じようにパースすることができますが、rooにできてrubyXLにはできないことの一つにexpand_merged_rangesがあります。 rooではexpand_merged_rangesを指定すると、ファイル取り込み時に結合されたセル全てで値が取得されます。 残念ながら、rubyXLにはこのような便利なオプションはないので、1セルしか取得されず、残りのセルはnilになります。

excel = RubyXL::Parser.parse('sample.xlsx')
sheet = excel[0]

excel_arr = sheet.map do |row|
  row.cells.map do |cell|
    cell.value
  end
end

p excel_arr
#=>[["hello world"], ["結合セル", nil], [nil, nil]]
しかし、rubyXLが結合セルの情報を持っていない訳ではありません。 merged_cellsメソッドを使うことで、結合セルの情報を取得することができます。
excel = RubyXL::Parser.parse('sample.xlsx')
sheet = excel[0]

excel_arr = sheet.map do |row|
  row.cells.map do |cell|
    cell.value
  end
end

#結合セルの情報を取得
reference = sheet.merged_cells[0].ref
row_num = [*reference.row_range]
col_num = [*reference.col_range]

#nilになっている結合セルに値を入れる
row_num.each do |row|
  col_num.each do |col|
    excel_arr[row][col] = excel_arr[row_num.first][col_num.first]
  end
end

p excel_arr
#=>[["hello world"], ["結合セル", "結合セル"], ["結合セル", "結合セル"]]

終わりに

今回はrubyXLをrooの代用として使う方法を紹介しました。rooで正常にできるに越したことはないですが、もし正常に取得できない時は rubyXLを代用してみてください

Pocket