Skip to content

Instantly share code, notes, and snippets.

@dsisnero
Forked from doju-m/xlshelper.rb
Created April 13, 2016 18:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsisnero/df89a4e94163b158f44bd4711119664b to your computer and use it in GitHub Desktop.
Save dsisnero/df89a4e94163b158f44bd4711119664b to your computer and use it in GitHub Desktop.
# -*- coding: windows-31j -*-
# Excelを扱うときの支援用
# 2012/10/17 吉田
require 'win32ole'
class XlsHelper
# 最初にExcelをインスタンス化したときに定数をインポートする
def self.const_init(xls)
unless self.const_defined?(:XlUp) # Excel定数の代表
WIN32OLE.const_load(xls, self)
end
end
# Excelインスタンスを取得する。
# ブロックを与えると、ブロックを抜けたところでExcelの終了を試みる。
def self.get_app()
xls = WIN32OLE.new('Excel.Application')
const_init(xls)
if block_given?
begin
yield(xls)
rescue => e
xls.Visible = true # 非常時に操作できるように
# Excelから来る例外メッセージにはエンコーディング情報がない
STDERR.puts e.message.force_encoding(ole_encoding)
e.backtrace.each do |t|
STDERR.puts t
end
ensure
xls.Workbooks.each do |bk|
bk.Saved = true
bk.Close
end
xls.Quit
end
xls = nil
else
xls
end
end
# 指定ブックにブロックの処理を適用し、終わればブックを閉じようとする。
def self.work_with_book(bk, &block)
unless block
raise ArgumentError("this method needs a block.")
end
begin
block.call(bk)
ensure
begin
bk.Saved = true # ブロック内で保存されていないなら、おそらくこの方が安全
bk.Close
rescue
# NOP
end
bk = nil
end
end
# 指定のExcelインスタンスでブックを開く。
# ブロックを与えると、ブロックを抜けたところでブックを閉じようとする。
def self.open_book_with(app, bk_file, &block)
bk = app.Workbooks.Open(bk_fullpath(bk_file))
if block.nil?
bk
else
work_with_book(bk) do |bk|
block.call(bk)
end
nil
end
end
# 指定のブックを開き、与えられたブロック内で処理する。
# Excelの起動/終了、ブックのクローズは自動的に行う。
# 単一のブックを処理する際の簡易メソッド。
def self.open_book(bk_file, &block)
unless block
raise ArgumentError("this method needs a block.")
end
get_app do |app|
open_book_with(app, bk_file) do |bk|
block.call(bk)
end
end
end
# ブック名もしくは序数に相当するブックを返す。
# 該当するブックが開いていなければnil。
def self.get_book(app, bk_idx)
get_item(app.Workbooks, bk_idx)
end
# ブック名もしくは序数に相当するブックがあるか否かを返す。
def self.has_book?(app, bk_idx)
has_item?(app.Workbooks, bk_idx)
end
# シート名もしくは序数に相当するシートを返す。
# 該当するシートがなければnil。
def self.get_sheet(bk, sht_idx)
get_item(bk.Worksheets, sht_idx)
end
# シート名もしくは序数に相当するシートがあるか否かを返す。
def self.has_sheet?(bk, sht_idx)
has_item?(bk.Worksheets, sht_idx)
end
# コレクションの中にidxに相当する要素があればそれを返す。
# なければnil。
def self.get_item(collection, idx)
if has_item?(collection, idx)
collection[idx]
else
nil
end
end
# コレクションの中にidxに相当する要素があるか否かを返す。
def self.has_item?(collection, idx)
result = false
case idx
when Numeric
result = (0 < idx and idx <= collection.Count)
when String, Symbol
n = ole_encode(idx.to_s)
collection.each do |e|
if e.Name == n
result = true
break
end
end
end
result
end
# 指定されたブックのパスを絶対パスにして返す。
# 以前は常にWindows-31Jエンコーディングで返していたが、
# 現在はそのときのWIN32OLE.codepageに応じたエンコーディングで返す。
def self.bk_fullpath(bk_file)
File.expand_path(ole_encode(bk_file)).gsub('/', '\\')
end
## 指定された文字列に対するWindows-31Jエンコーディングの文字列を返す。
#def self.local_encode(s)
# if s.encoding == Encoding::Windows_31J
# s.dup
# else
# s.encode(Encoding::Windows_31J)
# end
#end
# 指定された文字列に対するWIN32OLEコードページに応じたエンコーディングの文字列を返す。
def self.ole_encode(s)
enc = ole_encoding
if s.encoding == enc
s.dup
else
s.encode(enc)
end
end
# 現在のWIN32OLEコードページに対応するRubyエンコーディングを返す。
def self.ole_encoding
case WIN32OLE.codepage
when WIN32OLE::CP_ACP, WIN32OLE::CP_OEMCP
Encoding.default_external
when WIN32OLE::CP_SYMBOL
Encoding.ASCII_8BIT
when WIN32OLE::CP_UTF8
Encoding::UTF_8
when WIN32OLE::LOCALE_SYSTEM_DEFAULT, WIN32OLE::LOCALE_USER_DEFAULT
Encoding.default_external
else
Encoding.default_external
end
end
# 列番号から文字表記に変換する。
def self.colnum2letter(num)
if num == 0
''
else
q = num / 26
r = num % 26
if r == 0
q -= 1
r += 26
end
colnum2letter(q) + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[r - 1]
end
end
# 文字表記から列番号に変換する。
def self.colletter2num(l_col)
n = 0
l_col.each_char do |c|
p = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.index(c.upcase)
if p.nil?
break
end
n = n * 26 + (p + 1)
end
n
end
# セル番号で指定された矩形領域のRangeオブジェクトを返す。
def self.get_rectrange(sht, r1, c1, r2, c2)
sht.Range("%s%d:%s%d" % [colnum2letter(c1), r1, colnum2letter(c2), r2])
end
# VB色表現を得る。
def self.vbcolor(r, g, b)
(b & 0xFF) << 16 | (g & 0xFF) << 8 | (r & 0xFF)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment