見出し画像

面倒なExcel処理をPythonで自動化

1. まえがき

 箇条書きで複数の条件が一つのセルに記入されているExcelファイルの各々の条件を、それぞれ別のセルに分割してほしいと依頼されました。
 つまり下図のように別々のセルに分割したいようです。

 これが項番500もあれば、残業も覚悟の作業になるわけですが、こういった面倒で手間な処理はPythonで処理して楽しましょうってお話です。

2. まずは元となるExcelの条件を整理

  • 元ファイル名はcounter.xlsx

  • シートは1枚

  • 確認項目に(1)・・・ (2)・・・と複数条件が記述されている場合、枝番をつけて分割する。

  • 項番は500行、一つの項番に条件は最大で(20)まである。

3. PythonでExcelを利用するための環境構築

 PythonでExcelを扱うため「openpyxl」を利用します。バージョンは執筆時点の最新にしました。簡単な処理なので、最新いれておけば大丈夫でしょう。(お気楽感をアピール!)

% pip install openpyxl
     :
Successfully installed et-xmlfile-1.1.0 openpyxl-3.0.9
% 

4.コーディング

 あまり複雑に処理を書くのではなく、取り敢えず変更してCSVファイルにすれば、ExcelでCSVを開いてコピペできるようになるでしょう。これだけで、大分楽になるはずです。
 CSVの出力も、あえてCSVファイルに書く処理は書かずに、標準出力に表示して、リダイレクトでファイルに出力すればこの部分のコーディングは不要ですよね!
 今回は繰り返し使う処理ではなく、一時的な処理なんで、なるべく処理は簡単に!

 てことでソースファイル名をconv.pyとして、コーディングを開始します。
 まずはExcelファイルを開いて、シートを選択して、1行ずつ処理するところまで実装していきます。

import openpyxl

book = openpyxl.load_workbook('counter.xlsx')
sheet = book.active
for row in sheet.rows:
    print(row)

 続いて、B列の(=row[1])の分割を考えます。B列は(1)とか(2)といった括弧+数字で区切られているので、この条件で文字列を分割してみます。
 括弧+数字は、正規表現で「\(\d+\)」と表現できるので、正規表現で分割可能な、re.splitを使えば分割できそうですね。
(分割前に、余分な改行が気になったので改行は一旦削除してます。)

import re
import openpyxl

book = openpyxl.load_workbook('counter.xlsx')
sheet = book.active
for row in sheet.rows:
    col1 = row[1].value.replace('\n','')
    col1s = re.split('\(\d+\)',col1)

(Tips) 〜 正規表現 「\(\d+\)」について 〜
\d+ : 数字(d)が複数続く(+)ことを表す
\( , \) : これは()が正規表現で予約されているのでエスケープシーケンスしているだけ。
※ (で始まって、数字が複数続いて、)で終わるって感じです。

col1s = re.split('\(\d+\)',col1)とすると、文字列が(n)で分割されリストになります。これをさらにfor文で回して、CSVっぽく表示します。
for文で回す際に、リストの何番目かを枝番にしたいので、enumerateを使ってリストの添字を返すようにしてます。
print文で「項番(A列),枝番,分割した条件」の順で表示してます。

for i, c1 in enumrate(col1s):
    print('{},{},{}'.format(row[0].value, i, c1 )

さらにi=0は表示しないようにしたいので、下記の通り修正。
(三項演算子を使ってます。)

for i, c1 in enumrate(col1s):
    print('{},{},{}'.format(row[0].value, i !=0 else '' , c1 )

といった感じで一通り処理はかけました。完成したソースがこちらです。
(ちょっとコメントつけて、見やすくしました。)

import re
import openpyxl

# Excelファイル[counter.xlsx]を開いて、アクティブなシートを選択する。
book = openpyxl.load_workbook('counter.xlsx')
sheet = book.active

# 選択したシート(sheet)を1行ずつ処理
for row in sheet.rows:
        # A列:項番
      col0 = row[0].value

        # B列:確認項目の改行を削除
    col1 = row[1].value.replace('\n','')
        # B列:確認項目を(数字)単位で分割しcol1sにリスト形式で格納
    col1s = re.split('\(\d+\)',col1)

        # i = 添字 , c1 = 確認項目の条件
    for i, c1 in enumrate(col1s):
            # 項番,枝番,条件の順で表示 但し枝番0は''とし表示しない
        print('{},{},{}'.format(col0, i !=0 else '' , c1 )

 実行前に元のExcelの1行目のタイトル行の処理ができていませんが、プログラムを書くより、Excel開いて1行削除した方が早いので削除!

 早速実行します。

% pythononv.py
1,,サービス事業者は、○○を満たすことを、サービス利用者に説明する責任を果たすため、以下の責任を負うこと。
1,1,○○を文書化して提示すること。
1,2,○○に関する説明及び必要な情報提供を履行すること。
2,,サービスの利用者は、○○を履行すること。
 :
%

 良さそうなので、ファイルに出力

% python conv.py >counter.csv

 あとは、Excelでcounter.csvを文字コードutf-8を指定して開いて、元のファイルにペタッとはれば依頼された作業は完了です。

5. あとがき

 時間と精神がすり減りそうな繰り返し処理は、最近だとRPAを利用するっていうのを思いつく感じでしょうか。RPAはRPAで良い所もありますので、私はRPA否定派ではないですが、一からRPAを習得するなら、同じ手間でPython覚えるのも「有り?」って思っていただけたなら幸いです。

 プログラミングを覚えれば、数時間の処理が数行程度のコーディングで完了し、10分足らずで終わらせることが出来るようになりますよ!


この記事が気に入ったらサポートをしてみませんか?