テクセル

RubyでExcel操作


RubyでExcelの操作を行います。実行確認した環境は以下となります。

RubyによるExcel操作の例を下記に示します。実行には、「excelUtil.rb」、「wincons.rb」が必要です。
Excelユーティリティ「excelUtil.rb」(excelUtil_v100.7z)のダウンロード
「wincons.rb」の説明及びダウンロード


# coding: utf-8
# excel操作の例
require 'win32ole'
require "./excelUtil"
require "./wincons"

arfruits = [ [ "りんご", 3500 ],
             [ "なし",   3120 ],
             [ "みかん", 2950 ],
             [ "バナナ", 2800 ]
           ]

cons = Console.new(__ENCODING__)
exlUtil = ExcelUtilt.new()

excel = WIN32OLE.new('Excel.Application')

module ExlConst; end                        # excelの定数をロード
WIN32OLE.const_load(excel, ExlConst)

excel.visible = true                        # 表示状態とする

# ------- Excelファイルを読み込む場合
#sxlsfile = __dir__.encode("utf-8") + "/excel例1.xls"  # or xlsxファイル
#begin
#   workbook = excel.workbooks.Open(sxlsfile)
#rescue
#   print "excelファイル読み込みエラー!¥r¥n"
#   exit
#end
# ------- 新規でワークブックを追加する場合
workbook = excel.workbooks.add

sheets = workbook.Sheets
nshnm = "果物"                              # 新シート名
bz = false
sheets.each{|sht|
   if nshnm == sht.Name.encode("utf-8")     # 新シート名存在するか?
      bz = true
      break
   end
}
if bz == false
   sheets.Add.Name = nshnm                  # 新シート追加
end

sheet = workbook.sheets(nshnm)              # 「果物」シート選択
sheet.Activate                              # シートをアクティブに 前面表示
print "シート名:" + sheet.Name.encode("utf-8") + "¥r¥n"    # シート名取得

ix = 'B'.ord - 'A'.ord + 1; iy = 3          # B3
sheet.Cells(iy, ix).Value = "品名"
sheet.Cells(iy, ix + 1).Value = "金額"
oRange = sheet.range(sheet.Cells(iy, ix), sheet.Cells(iy, ix + 1))   # B3:C3
oRange.Interior.Color = exlUtil.rgb(0xff, 0, 0)     # バック色
oRange.Font.Color = exlUtil.rgb(0xff, 0xff, 0xff)   # 文字色
oRange.HorizontalAlignment = ExlConst::XlCenter   # 文字横方向中央
oRange.VerticalAlignment = ExlConst::XlCenter     # 文字縦方向中央

border = oRange.Borders(ExlConst::XlEdgeBottom)   # 罫線下端
border.LineStyle = ExlConst::XlContinuous         # 実線
border.Weight = ExlConst::XlMedium          # 太さ中
border.ColorIndex = 1                       # 色コード 1 黒

iy += 1
ssum = (ix + 'A'.ord).chr + iy.to_s
arfruits.each{|sf, ik|
   oCell = sheet.Cells(iy, ix)
   oCell.Value = sf
   oCell.Interior.Color = exlUtil.rgb(0xaa, 0xff, 0xff) # バック色
   oCell = sheet.Cells(iy, ix + 1)
   oCell.NumberFormatLocal = "#,##0"        # セルの表示形式
   oCell.Value = ik
   iy += 1
}
ssum += ":" + (ix + 'A'.ord).chr + (iy - 1).to_s

oCell = sheet.Cells(iy, ix)                 # B8
oCell.Value = "合計"
border = sheet.range(sheet.Cells(iy, ix), sheet.Cells(iy, ix + 1)).Borders(ExlConst::XlEdgeTop) # 罫線上端
border.LineStyle = ExlConst::XlContinuous
border.Weight = ExlConst::XlMedium
border.ColorIndex = 5                       # 色コード 5 青

oCell.Interior.Color = exlUtil.rgb(0, 0x80, 0)      # バック色
oCell.Font.Color = exlUtil.rgb(0xff, 0xff, 0xff)    # 文字色

oCell = sheet.Cells(iy, ix + 1)             # C8
oCell.formula = "=sum(" + ssum + ")"        # 合計関数
oCell.NumberFormatLocal = "¥¥#,##0"         # 表示形式 ¥付き
isum = oCell.Value
print "合計=" + isum.to_s + "¥r¥n"

iprn = 0
print "印刷しますか?(y/n)¥r¥n"
while true
   sleep 0.01
   ca = cons.inkey
   if ca[0] == nil; next; end
   if ca[0] == "y" || ca[0] == "Y"
      iprn = 1
   end
   break;
end

if iprn == 1                 # 印刷 印刷部数:1 開始ページ:1 終了ページ:1
   sheet.PrintOut(:Copies => 1, :From => 1, :To => 2)
end

print "qキーで終了¥r¥n"
while true
   ca = cons.inkey
   if ca[0] == "q" || ca[0] == "Q"
     break
   end
   sleep 0.01
end

sxlsfile = __dir__.encode("utf-8") + "/excel例3.xlsx" # or xlsファイル
print sxlsfile + "¥r¥n"
if File.exist?(sxlsfile)
   File.delete(sxlsfile)
end
workbook.SaveAs(sxlsfile.sub("/", "¥¥"))    # 名前を付けて保存

excel.quit
   

EXCEL実行結果
実行結果

下記プログラム例における オブジェクトexcel, workbook, sheet については、上記プログラムを参照してください。

1) 全般


module ExlConst; end          # excelの定数をロード
WIN32OLE.const_load(excel, ExlConst)

excel.visible = true          # 表示状態で実行 falseで非表示実行 false:デフォルト値   
   
excel.DisplayAlerts = false   # 確認メッセージを非表示 trueで表示

workbook.Saved = true         # 終了時の保存確認メッセージを非表示
   

EXCEL定数を使用する場合は、先頭文字を大文字にします。 例 xlCenter の場合 ExlConst::XlCenter

2) シート


sheet = workbook.ActiveSheet                # アクティブなシートを選択
sheet = workbook.sheets("Sheet1")           # シート名でシート選択
sheet = workbook.sheets[1]                  # インデックスNO.でシート選択 1~

sheet.Activate                              # 選択シートをアクティブに 前面に表示

sheet.Name = "新シート名"                   # 選択シートのシート名変更

icu = sheets.Count                          # シート数取得

# 全シート名取得
arshnm = []        # シート名を入れる配列
sheets.each{|sht|
   arshnm << sht.Name.encode("utf-8")
}
p arshnm

sheet = sheets.add                          # シートを追加 戻り値が追加シート
sheet = sheets.add(:after => workbook.sheets(sheets.count)) # 最後尾にシート追加

workbook.sheets("Sheet3").Move(:after => workbook.sheets("Sheet1")) # sheet3をsheet1の後ろに移動
workbook.sheets("Sheet3").Move(:before => workbook.sheets("Sheet1")) # sheet3をsheet1の前に移動

workbook.sheets("Sheet3").Delete            # Sheet3削除

sheet.Visible = false                       # 選択シートを非表示 trueで表示
   

3) セル


# セルに値セット
oCell = sheet.Cells(11, 2)                  # セル"B11"を指定 行,列で指定 1~の数字
oCell.Value = "千葉県"
oRange = sheet.range("B12")                 # セル"B12"をRangeで指定
oRange.Value = "日本"

# セルの値取得
va = sheet.Cells(2, 2).Value
va = sheet.Cells(3, 2).Value2               # 通貨型、日付型の場合 Flota型 日付型の場合はシリアル値
va = sheet.Cells(4, 2).Text                 # 表示した状態を取得
   

Value での取得データは、数字:Float型、文字列:String型、日付:Time型、通貨:String型 となります。
Value2 での取得データは、数字:Float型、文字列:String型、日付:Float型、通貨:Float型 となります。
Text での取得データは、すべてString型となります。
値のないセルを Value、Value2 で読み込んだ場合は、nil となり、Text で読み込んだ場合は、"" となります。


# B3:B4の内容を配列で読込
arrdd = sheet.range("B3:E4").Value
p arrdd

# B6:F7へ配列で書込
ardata = [["品名", "りんご", "みかん", "バナナ", "なし"],
          ["個数",       50,      80,       65,      45]]
sheet.range("B6:F7").Value = ardata

# コピーペースト  B2:E3 の内容を B5 へコピー
sheet.range("B2:E3").Copy
#sheet.range("B5").PasteSpecial             # すべて貼り付け
sheet.range("B5").PasteSpecial(:Paste => ExlConst::XlPasteValues)     # 値のみ貼り付け

# コピー状態を解除
excel.cutCopyMode = false

# B2:B3 の内容を B5 へコピー
sheet.range("B2:B3").Copy(:Destination => sheet.range("B5"))
sheet.range("B2:B3").Copy(sheet.range("B5")) # Destinationを省略した場合 

oRange.Clear                                # セル内容をすべてクリア
oRange.ClearContents                        # 数式、文字列クリア
oRange.ClearFormats                         # 書式クリア

# セルの書式例
oCell.NumberFormatLocal = "@"               # 表示形式を文字列に
oCell.NumberFormatLocal = "¥¥#,##0;[赤]¥¥-#,##0" # 通貨形式 マイナスで赤表示
oCell.NumberFormatLocal = "YYYY年MM月DD日"  # 日付形式 シリアル値を入力

oRange.Font.Name = "MS 明朝"              # フォント指定
oRange.Font.Italic = true                   # 斜体指定 falseで解除
oRange.Font.Bold = true                     # 太字指定 falseで解除
oRange.Font.Size = 15                       # フォントサイズ指定
oRange.Font.Underline = ExlConst::XlUnderlineStyleDouble    # 文字下線 二重線
oRange.Font.Strikethrough = true            # 取り消し線

sheet.range("B2:D2").MergeCells = true      # B2:D2をセル結合
sheet.range("B2:D2").MergeCells = false     # B2:D2のセル結合を解除
   

参考)
・セルの値を文字で読み込んだ場合、文字コードは、「Windows-31J」です。また、値の存在しないセルは、「nil」となります。
・セル内で改行がある場合は、改行コード0x0A(LF)がセットされます。
・セルへ代入する文字コードは、「utf-8」でも可能です。
・貼り付け内容 XlPasteType 列挙 (Excel)


# セルの幅取得
iw = sheet.Columns("B").Width                       # Width ポイント単位
iw = sheet.Columns(2).Width
iw = sheet.Columns("B").ColumnWidth                 # ColumnWidth 標準フォントの1文字単位
iw = sheet.Columns(2).ColumnWidth
iw = sheet.Range("B1").EntireColumn.Width
iw = sheet.Range("B1").EntireColumn.ColumnWidth     # ColumnWidth 標準フォントの1文字単位
iw = sheet.Range("C2").Width
iw = sheet.Range("D3").ColumnWidth

# セルの幅設定   Width での設定は不可
sheet.Columns(1).ColumnWidth = 10
sheet.Columns("B").ColumnWidth = 20
sheet.Range("C2").ColumnWidth = 40

# セルの高さ取得
ih = sheet.Rows(2).Height                           # 2行目 Height ポイント単位
ih = sheet.Rows(2).RowHeight                        # RowHeight ポイント単位
ih = sheet.Range("A2").EntireRow.Height             # 2行目
ih = sheet.Range("B2").EntireRow.RowHeight          # 2行目
ih = sheet.Range("C3").Height                       # 3行目
ih = sheet.Range("D4").RowHeight                    # 4行目

# セルの高さ設定   Height での設定は不可
sheet.Rows(3).RowHeight = 30                        # 3行目 30ポイント
sheet.Range("A4").EntireRow.RowHeight = 35          # 4行目 35ポイント
sheet.Range("A5").RowHeight = 40                    # 5行目 40ポイント
   

4) 色

色指定のプロパティは、ColorColorIndexの二通りあります。Colorは、RGB値で指定します。 ColorIndexは、1~56の色コードに対応した数字で指定します。
Colorは、Excel2007以降で使用出来ます。上記例におけるrgb関数は、excelUtil.rbで定義されています。


# ColorIndex出力例
ic = 1; iy = 2
ibc = 'A'.ord - 1
loop{
   'B'.upto('I'){|sx|
      ix = sx.ord - ibc
      oCell = sheet.Cells(iy, ix)
      oCell.Interior.ColorIndex = ic
      oCell.Value = ic
      oCell.Font.Bold = true 
      oCell.HorizontalAlignment = ExlConst::XlCenter
      ic += 1
   }
   if ic > 56; break; end
   iy += 1
}
   
ColorIndex

5) ワークシート関数を使う

Excelのワークシート関数を使います。すべての関数が使えるわけではありません。


# Max関数を使用 C4:C7での最大値を取得します。
imax = excel.WorksheetFunction.Max(sheet.Range("C4:C7"))
p imax

# Sum関数を使用 C4:C7での合計値を取得します。
isum = excel.WorksheetFunction.Sum(sheet.Range("C4:C7"))
p isum

# COUNTIF関数使用 C4:C7で「>=3000」の個数を取得します。
icu = excel.WorksheetFunction.COUNTIF(sheet.Range("C4:C7"), ">=3000")
p icu
   

6) セルの内容をクリップボード経由で読み書き

クリップボード経由のデータは、行の区切りが、¥r¥n(CRLF)でセルデータの区切りが¥t(タブ)となっています。また、 文字コードは、マジックコメントに従います。(utf-8または、Windows31-J) 下記プログラム例では、utf-8です。 プログラムの実行には、clipboard.rbが必要です。


# coding: utf-8
require 'win32ole'
require "./clipboard"

CBd = ClipBoard.new(__ENCODING__)

excel = WIN32OLE.new('Excel.Application')

excel.visible = true                        # 表示状態とする
sxlsfile = __dir__.encode("utf-8") + "/exlテスト用.xlsx"
workbook = excel.workbooks.Open(sxlsfile)

sheet = workbook.sheets("Sheet1")
sheet.Activate

sheet.Range("A1:D3").Copy              # A1:D3の内容をクリップボード経由で取得
sr = CBd.getText
print sr

sd = "品名¥tりんご¥tみかん¥tバナナ¥tなし¥r¥n" +
     "個数¥t50¥t80¥t65¥t45¥r¥n"
CBd.setText(sd)
sheet.Range("A5").PasteSpecial  # クリップボード経由でA5:E6へ書き込み

workbook.Saved = true           # 終了時の保存確認メッセージを非表示

excel.quit
   

7) 印刷関係


sheet.PageSetup.PrintArea = sheet.range("A1:D12").Address    # 印刷範囲設定
sheet.PageSetup.PrintArea = ""               # 印刷範囲解除

sheet.range("A6").PageBreak = ExlConst::XlPageBreakManual    # 改ページ設定 指定セルの上
sheet.range("A6").PageBreak = ExlConst::XlNone               # 改ページ解除
sheet.ResetAllPageBreaks                     # 全改ページ解除

# 印刷例
sheet.PrintOut(:From => 1,                # 開始ページ
               :To => 2,                  # 終了ページ
               :Copies =>1,               # 部数
               :Preview => true,          # プレビュー true:有り false:無し
               :ActivePrinter => "Microsoft XPS Document Writer") # 印刷プリンタを指定
   

印刷ダイアログを表示します。ダイアログ表示参照


excel.Dialogs(ExlConst::XlDialogPrint).Show
   

パソコン内のプリンタ一覧を取得します。PrintOutで指定するプリンタ名は、下記プログラムで取得出来ます。


# coding: utf-8
require 'win32ole'

appShell = WIN32OLE.new('Shell.Application')
prnObj = appShell.NameSpace(4).Items
ik = prnObj.count;           # プリンタ数
for ia in 0..(ik - 1) do
   p prnObj.item(ia).Name
end
   

8) PDFファイル出力

アクティブシートをPDFファイル出力します。


sheet.PageSetup.PrintArea = sheet.range("A1:I30").Address  # 出力範囲設定
sheet.range("A20").PageBreak = ExlConst::XlPageBreakManual # 改ページ位置
workbook.ActiveSheet.ExportAsFixedFormat(:Type => ExlConst::XlTypePDF, # TYPE PDF形式指定
   :Filename => "d:¥¥pdffile¥¥pdfテスト.pdf",  # 出力するPDFファイル名
   :Quality => ExlConst::XlQualityStandard,  # ファイルの品質 or XlQualityMinimum
   :IncludeDocProperties => true,            # ドキュメント プロパティを含める場合はtrue、それ以外はfalse
   :IgnorePrintAreas => false,               # 印刷範囲を無視する場合はtrue、それ以外はfalse
   :OpenAfterPublish => false,               # 出力後にpdf表示を行う場合はtrue、それ以外はfalse
   :From => 1,                               # 開始ページ 省略時は、先頭ページ
   :To => 2)                                 # 終了ページ 省略時は、最終ページ

# 簡易出力   
workbook.ActiveSheet.ExportAsFixedFormat(:Type => ExlConst::XlTypePDF, :Filename => "d:¥¥pdffile¥¥pdfテスト.pdf")
   

9) InputBox

ExcelのメソッドInputBoxを使用します。


# Prompt(省略不可), Title(省略可) 指定
sr = excel.InputBox("名前を入力して下さい。", "入力")
sr = excel.InputBox("名前を入力して下さい。", :Title => "名前入力") # 引数名Title指定
sr = excel.InputBox("住所を入力して下さい。¥r¥n都道府県名から入力して下さい。", "入力") # Promptに改行ありの場合
if sr != false                              # 「キャンセル」ボタンが押された場合は、戻り値がfalseとなります。
   print sr + "¥r¥n"
end  

# キー入力制限をTypeで指定
dr = excel.InputBox("個数を入力して下さい。", "入力", :Type => 1) # 数字入力限定 2:文字列
if dr != false
   print dr.to_s + "¥r¥n"                   # 戻り値は、float
end
   

・引数XPos(Left),YPos(Top),Defaultは、使用出来ません。

10) ダイアログ表示

Excelのダイアログを表示します。


# [名前を付けて保存] ダイアログ ボックス
excel.Dialogs(ExlConst::XlDialogSaveAs).Show

# [ページ設定 (ページ)] ダイアログ ボックス
excel.Dialogs(ExlConst::XlDialogPageSetup).Show

# [印刷] ダイアログ ボックス
 excel.Dialogs(ExlConst::XlDialogPrint).Show

# [プリンターの設定] ダイアログ ボックス
excel.Dialogs(ExlConst::XlDialogPrinterSetup).Show

# [印刷プレビュー] ダイアログ ボックス
excel.Dialogs(ExlConst::XlDialogPrintPreview).Show
   

ダイアログは、上記以外にもあります。ダイアログ一覧(XlBuiltInDialog 列挙) すべてのダイアログの動作を確認していませんので、使用時は確認を行い使用して下さい。

11) Excelのマクロを実行

RubyからExcelのマクロを実行します。Excelファイルは、「マクロテスト.xlsm」とします。


' Rubyから実行するExcelマクロの例
Sub test()

   msgdisp ("マクロのテスト")
End Sub

Sub msgdisp(ByVal smsg As String)

   MsgBox smsg
End Sub

Function add(ByVal ix As Integer, ByVal iy As Integer)

   add = ix + iy
End Function

Function inputStr(ByVal smsg As String)

   inputStr = InputBox(smsg)
End Function
   

上記ExcelマクロをRubyから実行します。


# coding: utf-8
# excelのマクロ実行例
require 'win32ole'

excel = WIN32OLE.new('Excel.Application')
excel.visible = true

sxlsfile = __dir__.encode("utf-8") + "/マクロテスト.xlsm"
begin
   workbook = excel.workbooks.Open(sxlsfile)
rescue
   puts "excelファイル読み込みエラー!"
   exit
end

excel.Run("test")                                     # 引数なし

excel.Run("msgdisp", "rubyからExcelマクロ実行")       # 引数文字列

ia = excel.Run("add", 3, 7)                           # 引数整数 戻り値整数
puts "加算値=" + ia.to_s

sa = excel.Run("inputStr", "名前を入力して下さい。")  # 引数文字列 戻り値文字列
puts "名前:" + sa.encode("utf-8")

excel.quit
   
参考
Win32OLE 活用法 【第 2 回】 Excel

履歴(excelUtil.rb)

2017.05 Ver.1.00 excelconst.rbから変更
Rubyユーティリティ
©2015-2023 TEXCELL CORPORATION
テクセル株式会社