【DX推進の落とし穴?】中小企業のExcel活用と隠れた課題に迫る!

関数チェッカー プロジェクトN
この記事は約10分で読めます。
import openpyxl
import re
import logging
import os

# ロギングの設定
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def analyze_excel(file_path):
    """
    指定されたExcelファイルの情報を解析し、使用されている機能の数と件数をシートごとに表示する関数。

    Args:
        file_path (str): 解析するExcelファイルのパス。

    Returns:
        dict: 解析結果を格納した辞書。
              エラー発生時はNoneを返す。
    """
    logging.info(f"解析を開始します: {file_path}")
    analysis_result = {}

    try:
        workbook = openpyxl.load_workbook(file_path)
        logging.info("Excelファイルの読み込みが完了しました。")
    except FileNotFoundError:
        logging.error(f"エラー:ファイルが見つかりません - {file_path}")
        return None
    except Exception as e:
        logging.error(f"エラー:Excelファイルの読み込みに失敗しました - {e}")
        return None

    # 関数をカウントするための正規表現パターン
    function_pattern = re.compile(r"([A-Z]+)\(")

    logging.info(f"シート数: {len(workbook.sheetnames)}")
    for sheet_name in workbook.sheetnames:
        analysis_result[sheet_name] = {'関数': {}}
        sheet = workbook[sheet_name]
        for row in sheet.iter_rows():
            for cell in row:
                # セルの数式をチェック
                if cell.value and isinstance(cell.value, str) and cell.value.startswith('='):
                    functions = function_pattern.findall(cell.value)
                    for func in functions:
                        func_name = func.upper()
                        analysis_result[sheet_name]['関数'][func_name] = analysis_result[sheet_name]['関数'].get(func_name, 0) + 1


    # VBAの存在をチェック
    analysis_result['VBA'] = 1 if workbook.vba_archive else 0
    logging.info(f"VBAプロジェクトを検出しました。") if workbook.vba_archive else logging.info("VBAプロジェクトは検出されませんでした。")

    # マクロの存在をチェック
    try:
        if hasattr(workbook, 'macros') and workbook.macros:
            analysis_result['マクロ'] = len(workbook.macros)
            logging.info(f"マクロを検出しました - {len(workbook.macros)}個")
        else:
            analysis_result['マクロ'] = 0
            logging.info("マクロは検出されませんでした。")
    except AttributeError:
        logging.warning(f"  ワークブックにマクロ属性がありません。")
        analysis_result['マクロ'] = 0

    workbook.close()
    logging.info("解析が完了しました。")
    return analysis_result

def display_analysis_result(result, output_excel=False):
    """
    解析結果を見やすく表示する関数。

    Args:
        result (dict): 解析結果を格納した辞書。
        output_excel (bool, optional): 結果をExcelファイルに出力するかどうか。デフォルトはFalse。
    """
    if result is None:
        print("解析に失敗しました。ログを確認してください。")
        return

    print("\nExcelファイル解析結果:")
    print("------------------------")
    for sheet_name, sheet_result in result.items():
        if sheet_name in ['VBA', 'マクロ']:  # VBAとマクロはシートごとではないのでスキップ
            continue
        print(f"\nシート名: {sheet_name}")
        print("------------------------")
        print("関数:")
        if sheet_result.get('関数'): #  シートに'関数'キーが存在するか確認
            for func, count in sheet_result['関数'].items():
                print(f"  {func}: {count}個")
        else:
            print("  使用されている関数はありません")
    print(f"VBA:{'あり' if result.get('VBA', 0) else 'なし'}") #  resultに'VBA'キーが存在するか確認
    print(f"マクロ:{result.get('マクロ', 0)}個") #  resultに'マクロ'キーが存在するか確認
    print("------------------------")

    if output_excel:
        output_wb = openpyxl.Workbook()
        for sheet_name, sheet_result in result.items():
            if sheet_name in ['VBA', 'マクロ']:  # VBAとマクロはシートごとではないのでスキップ
                continue
            output_sheet = output_wb.create_sheet(title=sheet_name)
            headers = ["項目", "種類", "個数"]
            output_sheet.append(headers)
            if sheet_result.get('関数'): # シートに'関数'キーが存在するか確認
                for func, count in sheet_result['関数'].items():
                    output_sheet.append(["関数", func, count])
            else:
                output_sheet.append(["関数", "使用なし", 0])
        # VBAとマクロの結果を最初のシートに追記
        if 'Sheet' in output_wb.sheetnames:
            output_sheet = output_wb['Sheet']
        else:
            output_sheet = output_wb.active
        output_sheet.append(["VBA", "", "あり" if result.get('VBA', 0) else "なし"]) # resultに'VBA'キーが存在するか確認
        output_sheet.append(["マクロ", "", result.get('マクロ', 0)]) # resultに'マクロ'キーが存在するか確認

        output_file_name = "excel_analysis_result.xlsx"
        try:
            output_wb.save(output_file_name)
            print(f"解析結果をExcelファイルに保存しました: {output_file_name}")
        except Exception as e:
            print(f"エラー:Excelファイルへの保存に失敗しました - {e}")

if __name__ == "__main__":
    # Google Colab環境かどうかを判定
    try:
        from google.colab import files
        # ファイルアップロードダイアログを表示
        uploaded = files.upload()
        if uploaded:
            # アップロードされた最初のファイルのパスを取得
            file_path = list(uploaded.keys())[0]
            logging.info(f"アップロードされたファイル: {file_path}")
        else:
            logging.error("ファイルがアップロードされませんでした。")
            print("エラー:ファイルがアップロードされませんでした。")
            exit()
    except ImportError:
        # Google Colab環境でない場合は、ローカルファイルのパスを入力
        file_path = input("解析するExcelファイルのパスを入力してください: ")
        if not os.path.exists(file_path):
            print(f"エラー:指定されたパスにファイルが存在しません: {file_path}")
            exit()  # プログラムを終了する

    analysis_result = analyze_excel(file_path)
    if analysis_result:
        display_analysis_result(analysis_result, output_excel=True)

コメント

タイトルとURLをコピーしました