以下に掲げるrubyスクリプトのサンプルは、Excel操縦用ライブラリ exlap.rb ver 1.12: exlap112.zipに同梱のものを利用するとの前提で書かれています。
Excelの条件付き書式には信頼性に欠ける面があると感じています。正しくスクリプトを書いているはずなのに、意図した結果が得られないことがあります。
私の乏しい経験ではありますが、次の3点に沿ってスクリプトを書くと、比較的思いどおりの結果が得られやすい感じがします。
目次
#! ruby -Ks
# 条件付き書式: 氏名と性別からなる表。性別欄の色分け。女を赤、男を青
# XlCellValue(「セルが」)を使用:「数式が」ではない
require "exlap"
filename = "fc01.xls"
Exlap.new(filename) do |wb|
ss = wb.fes # 空のワークシートを選択
rng = ss.Range("A1:B4")
rng.Value = [%w(安部 男), %w(加藤 女), %w(佐々木 男), %w(田中 女)]
ss.range_each(rng) do |cell| # 領域内のセルを一つづつなぞる
cell.FormatConditions.Delete # 既存の条件付き書式を削除
# ↑ この事例では既存のものがないので必要ないが参考まで
fc1 = cell.FormatConditions.Add(XlCellValue, XlEqual, "女")
fc1.Font.ColorIndex = 3 # 赤
fc2 = cell.FormatConditions.Add(XlCellValue, XlEqual, "男")
fc2.Font.ColorIndex = 5 # 青
end
wb.save
end
download fc01.rb
#! ruby -Ks
# 条件付き書式: 氏名と性別からなる表。性別欄の色分け。女を赤、男を青
# XlExpression(「数式が」)を使用:「セルが」ではない
require "exlap"
filename = "fc01b.xls"
Exlap.new(filename) do |wb|
ss = wb.fes # 空のワークシートを選択
rng = ss.Range("A1:B4")
rng.Value = [%w(安部 男), %w(加藤 女), %w(佐々木 男), %w(田中 女)]
ss.range_each(rng) do |cell| # 領域内のセルを一つづつなぞる
fc1 = cell.FormatConditions.Add(XlExpression, nil, '=RC="女"')
fc1.Font.ColorIndex = 3 # 赤
fc2 = cell.FormatConditions.Add(XlExpression, nil, '=RC="男"')
fc2.Font.ColorIndex = 5 # 青
end
wb.save
end
download fc01b.rb
#! ruby -Ks
# 条件付き書式: 氏名と性別からなる表。氏名欄と性別欄の両方の色を変える。
require "exlap"
filename = "fc01c.xls"
Exlap.new(filename) do |wb|
ss = wb.fes # 空のワークシートを選択
rng = ss.Range("A1:B4")
rng.Value = [%w(安部 男), %w(加藤 女), %w(佐々木 男), %w(田中 女)]
ss.range_each(rng, :YX) do |y,x| # 領域内のセルをy,x座標数で一つづつなぞる
cell = ss.cell(y,x) # 現在注目セル
sex = Exl::relrc([y,2], [y,x]) # 現在位置から見た性別欄の相対番地
# ↑ sex => "RC[1]" | "RC"
# 女性の場合の設定
formula = "=#{sex}=\"女\""
fc1 = cell.FormatConditions.Add(XlExpression, nil, formula)
fc1.Font.ColorIndex = 3 # 赤
# 男性の場合の設定
formula = "=#{sex}=\"男\""
fc2 = cell.FormatConditions.Add(XlExpression, nil, formula)
fc2.Font.ColorIndex = 5 # 青
end
wb.save
end
download fc01c.rb
#! ruby -Ks
# 条件付き書式: 3×3領域に 1〜9を書き込み、4以上・6以下を赤にする
# XlCellValue(「セルが」)を使用:Formula2を用いる例
require "exlap"
filename = "fc02.xls"
Exlap.new(filename) do |wb|
ss = wb.fes # 空のワークシートを選択
rng = ss.Range("A1:C3")
rng.Value = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ss.range_each(rng) do |cell| # 領域内のセルを一つづつなぞる
fc = cell.FormatConditions.Add(XlCellValue, XlBetween, 4, 6)
# ↑ 最後の引数 6 が Formula2 の値
fc.Font.ColorIndex = 3 # 赤
end
wb.save
end
download fc02.rb
#! ruby -Ks
# 条件付き書式: 3×3領域に 1〜9を書き込み、4以上・6以下を赤にする
# XlExpression(「数式が」)を使用:Formula2は用いない
require "exlap"
filename = "fc02b.xls"
Exlap.new(filename) do |wb|
ss = wb.fes # 空のワークシートを選択
rng = ss.Range("A1:C3")
rng.Value = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ss.range_each(rng) do |cell| # 領域内のセルを一つづつなぞる
formula = "=AND(RC>=4,RC<=6)"
fc = cell.FormatConditions.Add(XlExpression, nil, formula)
fc.Font.ColorIndex = 3 # 赤
end
wb.save
end
download fc02b.rb
#! ruby -Ks
# 条件付き書式: 3×3領域に乱数をセットして、
# 各欄の値が平均値未満なら赤色にする。
require "exlap"
filename = "fc03.xls"
Exlap.new(filename) do |wb|
ss = wb.fes # 空のワークシートを選択
rng = ss.Range("A1:C3")
ss.range_each(rng) do |cell| # 領域内のセルを一つづつなぞる
cell.Value = rand(100) + 1 # 1〜100の整数(乱数)
end
ss.Range("A5").Value = "平均値:"
avg = ss.Range("B5")
avg.Formula = "=AVERAGE(#{Exl::relrc(rng,avg)})"
# ↑ Exl::relrc(rng,avg) => "R[-4]C[-1]:R[-2]C[1]"
ss.range_each(rng) do |cell|
formula = "=RC<#{Exl::relrc(avg,cell)}" # セルの値が平均値未満
fc = cell.FormatConditions.Add(XlExpression, nil, formula)
fc.Font.ColorIndex = 3 # 赤
end
wb.save
end
download fc03.rb
#! ruby -Ks
# 条件付き書式の「条件」の情報を出力。Type, Operator, Formula1, Formula2
require "exlap"
keys = %w(Type Operator Formula1 Formula2)
types = {1=>'XlCellValue', 2=>'XlExpression'}
oprs = {1=>'XlBetween', 2=>'XlNotBetween', 3=>'XlEqual', 4=>'XlNotEqual',
5=>'XlGreater', 6=>'XlLess', 7=>'XlGreaterEqual', 8=>'XlLessEqual'}
file_list = Dir.glob("./*.xls")
if file_list.size < 1 # xlsファイルがみつからない
exit
end
puts '条件付き書式の「条件」の情報を出力'
Exlap.new(*file_list) do |wb|
printf("WorkBook: %s\n", wb.name)
wb.each do |ss|
next if ss.empty?
printf("WorkSheet: %s\n", ss.Name)
fc_hs = {} # FormatConditionsの情報をHash形式でこれに記録
ss.range_each do |cell|
next if cell.FormatConditions.Count < 1 # 条件付き書式がない
addr = Exl::a1(cell) # セルの相対番地 A1, B1 など
ary = [] # 複数の「条件」をこれに記録
cell.Activate
cell.FormatConditions.each do |fc|
fcs = [] # 一つの「条件」をこれに記録
keys.each do |name|
scr = "fcs << (fc.#{name} rescue nil)"
eval(scr)
if fcs.last
case name
when 'Type'
fcs[-1] = types[fcs.last] if types[fcs.last]
when 'Operator'
fcs[-1] = oprs[fcs.last] if oprs[fcs.last]
end
end
end
ary << fcs
end
w = fc_hs[ary]
fc_hs[ary] = !w ? addr : "#{w} #{addr}"
end
if fc_hs.size > 0
fc_info = []
fc_hs.each {|ary, addr| fc_info << [addr, ary]}
fc_info.sort.each do |addr, ary|
puts addr
ary.each do |fcs|
str = "\t"
keys.each_index {|i| str += "#{keys[i]} #{fcs[i]}, " if fcs[i]}
puts str.sub(/, +$/, "")
end
end
end
printf("\n")
end
end
download fc04.rb