概要
以下のような Excel ファイルを、
以下のように色付けし、1つ上のセルと比較して変更されている箇所を分かりやすくしたい。
実行イメージ (ゴール)
Python バージョン
3.8.2
実行手順
- venv などで仮想環境を構築する
pip install -r requirements.txt
- 対象とする Excel ファイルを開く
-
python main.py
- 引数として
all
を渡す: アクティブブック内の全てのシートに対して適用する - 引数を渡さない: アクティブブック内のアクティブシートのみに適用する
- 引数として
コード
requirements.txt
xlwings
xlsxwriter
settings.py
import xlwings as xw
from xlsxwriter.utility import xl_col_to_name
# 1つ上のセルと値が違う際に使用する背景色 (RGB)
background_color = (252, 228, 214)
# 1つ上のセルと値が同じ際に使用する文字色 (RGB)
font_color = (191, 191, 191)
def make_target_cell_range(sheet: xw.Sheet) -> str:
"""
実行対象とするセルの範囲を 'A1:C5' のような形式の文字列で返す
Excel ファイルの内容に応じて処理を修正する必要あり
"""
# 列の開始と終了地点のアルファベットを取得
start_col_alphabet = None
end_col_alphabet = None
for cell in sheet.used_range:
if cell.value == '操作':
start_col_alphabet = xl_col_to_name(cell.column - 1)
if cell.value == '想定結果':
end_col_alphabet = xl_col_to_name(cell.column - 2)
break
# 行の開始と終了地点の番号を取得
a_col_values = list(map(lambda a: a.value, sheet.used_range.columns[0]))
a_col_nums = list(filter(lambda a: isinstance(a, float), a_col_values))
min_num = min(a_col_nums)
max_num = max(a_col_nums)
start_row_num = a_col_values.index(min_num) + 1
end_row_num = a_col_values.index(max_num) + 1
# 列のアルファベットと行番号を 'A1:C5' のように形に連結して返す
return start_col_alphabet + str(start_row_num) + ':' + end_col_alphabet + str(end_row_num)
main.py
from settings import *
import xlwings as xw
import sys
def sheet_to_readable(
sheet: xw.Sheet,
range_str: str,
):
"""
エクセルの1シートと、対象とするセルの範囲を受け取り、色付けして読みやすくする
:param sheet: Excel ファイルの1シート
:param range_str: 実行対象とするセルの範囲。例: 'A1:C5'
"""
for col in sheet.range(range_str).columns:
# 1つ上のセルの値
prev_value = None
for cell in col:
# 背景色をリセット
if cell.color == background_color:
cell.color = None
# 文字色をリセット
if cell.font.color == font_color:
cell.font.color = (0, 0, 0)
value = cell.value
if (value != prev_value) and (value is None):
pass
elif value != prev_value:
cell.color = background_color
else:
cell.font.color = font_color
prev_value = value
def main():
# Excel ファイルが開かれていない場合は処理を終える
if len(xw.books) <= 0:
print('対象とする Excel ファイルを開いてから再度実行してください。')
return
# 受け取った引数内に 'all' という文字列が含まれている場合、
# アクティブブック内の全てのシートに適用する
if (len(sys.argv) >= 2) and ('all' in sys.argv[1]):
book = xw.books.active
for sheet in book.sheets:
sheet.activate()
sheet_to_readable(sheet, make_target_cell_range(sheet))
# アクティブブック内のアクティブシートのみに適用する
else:
sheets = xw.sheets
sheet = sheets.active
sheet.activate()
sheet_to_readable(sheet, make_target_cell_range(sheet))
print('🚀 Success')
if __name__ == '__main__':
main()