異なるブックの2つシートを比較して差異のある部分を抽出

異なるブックの2つシートを比較して差異のある部分を抽出する。

2つのシートの内容を比較して差異がある部分を抽出する機能をVBAで作成しています。
比較できる内容はセルに入力された 値、数式、文字色と背景色、フォントに差異があればそのセルの情報が出力されるようになっています。

サンプルコードでは下記のような「設定シート」に比較したいシートなどの情報を指定し、その情報を元に比較を行います。
 ※設定シートを自動で作成するコードをページ下部(リンクからその箇所に移動します)に記載しています。
差異の比較ができる内容は設定フラグ(C8~C11セル)を用いることで比較させたい内容の選択ができます。

動作確認
Windows10/Excel2016:○
Windows11/Excel2024:○

設定シート

 ●シートの比較


Const SHT_PARM = "設定シート"
Const SHT_RESULT = "比較結果"

'******************************************************************
' シート比較
'******************************************************************
Sub Main_Compare()
    
    '初期化
    ThisWorkbook.Activate
    
    '比較結果のシートが無ければ作成
    If Not ChkExistSheet(ThisWorkbook, SHT_RESULT) Then
        Sheets.Add After:=Sheets(SHT_PARM)
        ActiveSheet.Name = SHT_RESULT
    Else
        Sheets(SHT_RESULT).Cells.Clear
    End If
    
    '入力値チェック
    Dim sBookName(1) As String
    sBookName(0) = Sheets(SHT_PARM).Range("D4")
    sBookName(1) = Sheets(SHT_PARM).Range("D5")
    
    Dim sBaseSheet(1) As String
    sBaseSheet(0) = Sheets(SHT_PARM).Range("E4")
    sBaseSheet(1) = Sheets(SHT_PARM).Range("E5")
    
    If sBookName(0) = "" Or sBookName(1) = "" Or _
       sBaseSheet(0) = "" Or sBaseSheet(1) = "" Then
        MsgBox "比較対象のブック、またはシート名が入力されていません。"
        Exit Sub
    End If
    
    '設定パラメータ作成
    Dim i As Long
    Dim sChkPram(3) As String
    For i = 0 To 3
        sChkPram(i) = CStr(Sheets(SHT_PARM).Cells(i + 8, 3))
    Next
    
    
    'ブックを開く
    Dim oBook(1) As Object
    Set oBook(0) = Workbooks.Open(sBookName(0))
    Set oBook(1) = Workbooks.Open(sBookName(1))
    
    
    '比較対象シートの存在チェック
    For i = 0 To 1
        If Not (ChkExistSheet(oBook(i), sBaseSheet(i))) Then
            MsgBox oBook(i).Name & "に" & vbCrLf & sBaseSheet(i) & "シートがありません。"
            oBook(0).Close
            oBook(1).Close
            Exit Sub
        End If
    Next
    
    'シートオブジェクト取得
    Dim oSheet(1) As Object
    Set oSheet(0) = oBook(0).Worksheets(sBaseSheet(0))
    Set oSheet(1) = oBook(1).Worksheets(sBaseSheet(1))

    'シート比較
    Call CompareSheet(oSheet, sChkPram)
    
    '結果シートの整形
    Call formatResultSht
    
    oBook(0).Close False
    oBook(1).Close False
    
End Sub

'******************************************************************
' シート存在チェック
'------------------------------------------------------------------
'  第1引数:ブックオブジェクト
'  第2引数:テキストファイルのパス
'------------------------------------------------------------------
'  戻り値 :確認結果(True:シートあり、False:シートなし)
'******************************************************************
Function ChkExistSheet(getBk As Object, getShtNm As String)
    ChkExistSheet = False
    
    Dim oChkObj As Object
    For Each oChkObj In getBk.Sheets
        If getShtNm = oChkObj.Name Then
            ChkExistSheet = True
            Exit For
        End If
    Next

End Function


'******************************************************************
' シート比較
'------------------------------------------------------------------
'  第1引数:シートオブジェクト
'  第2引数:比較対象の設定
'******************************************************************
Sub CompareSheet(getSht() As Object, getPram() As String)
    
    'シートの比較範囲を取得
    Dim lRow As Long
    Dim lCol As Long
    Call getCompareRange(getSht(), lRow, lCol)
    
    '出力用のブックをアクティブにする
    ThisWorkbook.Activate: Sheets(SHT_RESULT).Select
    
    '比較範囲を結果に出力
    Sheets(SHT_RESULT).Range("F2") = "A1~" & Cells(lRow, lCol).Address(0, 0)
    
    
    '比較実行
    Dim i As Long   'Row
    Dim j As Long   'Column
    Dim k As Long   '記載行
    k = 4
    With Sheets(SHT_RESULT)
        For i = 1 To lRow: For j = 1 To lCol
            '値
            If (getPram(0) = "1") And _
               (getSht(0).Cells(i, j).Text <> getSht(1).Cells(i, j).Text) Then
                .Cells(k, 2) = getSht(0).Cells(i, j).Address(0, 0)
                .Cells(k, 3) = "値"
                .Cells(k, 4) = getSht(0).Cells(i, j).Text
                .Cells(k, 5) = getSht(1).Cells(i, j).Text
                .Cells(k, 6) = ""
                k = k + 1
            End If
                
            '数式(Formulaの先頭文字が"="であれば数式と判断)
            If (getPram(1) = "1") And _
               (Left(getSht(0).Cells(i, j).Formula, 1) = "=" And _
                Left(getSht(1).Cells(i, j).Formula, 1) = "=") Then
                If getSht(0).Cells(i, j).Formula <> getSht(1).Cells(i, j).Formula Then
                    .Cells(k, 2) = getSht(0).Cells(i, j).Address(0, 0)
                    .Cells(k, 3) = "数式"
                    .Cells(k, 4) = "'" & getSht(0).Cells(i, j).Formula
                    .Cells(k, 5) = "'" & getSht(1).Cells(i, j).Formula
                    .Cells(k, 6) = "※数式表示の為、文字の先頭にシングルクォーテーション(')を付与。"
                    k = k + 1
                End If
            End If
            
            '文字色・背景色
            If (getPram(2) = "1") Then
                If (getSht(0).Cells(i, j).Font.Color <> getSht(1).Cells(i, j).Font.Color) Or _
                   (getSht(0).Cells(i, j).Interior.Color <> getSht(1).Cells(i, j).Interior.Color) Then
                    .Cells(k, 2) = getSht(0).Cells(i, j).Address(0, 0)
                    .Cells(k, 3) = "文字色・背景色"
                    .Cells(k, 4) = getSht(0).Cells(i, j).Text
                    .Cells(k, 5) = getSht(1).Cells(i, j).Text
                    .Cells(k, 4).Font.Color = getSht(0).Cells(i, j).Font.Color
                    .Cells(k, 5).Font.Color = getSht(1).Cells(i, j).Font.Color
                    .Cells(k, 4).Interior.Color = getSht(0).Cells(i, j).Interior.Color
                    .Cells(k, 5).Interior.Color = getSht(1).Cells(i, j).Interior.Color
                    .Cells(k, 6) = ""
                    k = k + 1
                End If
            End If
                
            'フォント
            If (getPram(3) = "1") And _
               (getSht(0).Cells(i, j).Font.Name <> getSht(1).Cells(i, j).Font.Name) Then
                .Cells(k, 2) = getSht(0).Cells(i, j).Address(0, 0)
                .Cells(k, 3) = "フォント"
                .Cells(k, 4) = getSht(0).Cells(i, j)
                .Cells(k, 5) = getSht(1).Cells(i, j)
                .Cells(k, 4).Font.Name = getSht(0).Cells(i, j).Font.Name
                .Cells(k, 5).Font.Name = getSht(1).Cells(i, j).Font.Name
                .Cells(k, 6) = getSht(0).Cells(i, j).Font.Name & " / " & getSht(1).Cells(i, j).Font.Name
                k = k + 1
            End If
    
        Next: Next
    End With

End Sub

'******************************************************************
' シートの比較範囲を取得
'------------------------------------------------------------------
'  第1引数:シートオブジェクト
'  第2引数:行番号(戻り値)
'  第3引数:列番号(戻り値)
'******************************************************************
Sub getCompareRange(getSht() As Object, ByRef rtnRow As Long, ByRef rtnCol As Long)
    
    '比較範囲の取得
    Dim lMaxRow(1) As Long
    Dim lMaxCol(1) As Long
    
    '1つ目のシートの使用範囲を取得
    With getSht(0)
        lMaxRow(0) = .UsedRange.Item(.UsedRange.Count).Row
        lMaxCol(0) = .UsedRange.Item(.UsedRange.Count).Column
    End With

    '2つ目のシートの使用範囲を取得
    With getSht(1)
        lMaxRow(1) = .UsedRange.Item(.UsedRange.Count).Row
        lMaxCol(1) = .UsedRange.Item(.UsedRange.Count).Column
    End With

    '行列の最大値を取得し比較範囲を設定
    Dim lRow As Long
    If lMaxRow(0) >= lMaxRow(1) Then
        rtnRow = lMaxRow(0)
    Else
        rtnRow = lMaxRow(1)
    End If
    
    Dim lCol As Long
    If lMaxCol(0) >= lMaxCol(1) Then
        rtnCol = lMaxCol(0)
    Else
        rtnCol = lMaxCol(1)
    End If
    
End Sub

'******************************************************************
' 比較結果シートの整形
'******************************************************************
Sub formatResultSht()
    
    ThisWorkbook.Activate
    With Sheets(SHT_RESULT)
        
        'ヘッダの設定
        .Range("B1") = "比較結果"
        .Range("B3") = "差異セル"
        .Range("C3") = "比較対象"
        .Range("D2") = Sheets(SHT_PARM).Range("D4")
        .Range("E2") = Sheets(SHT_PARM).Range("D5")
        .Range("D3") = Sheets(SHT_PARM).Range("E4")
        .Range("E3") = Sheets(SHT_PARM).Range("E5")
        .Range("F2") = "比較のセル範囲 : " + .Range("F2")
        .Range("B2:F3").Interior.Color = 14348257
        
        '列幅の設定
        .Columns("B").ColumnWidth = 8.5
        .Columns("C").ColumnWidth = 14.5
        .Columns("D:E").ColumnWidth = 32
        .Columns("F").ColumnWidth = 60
        
        '罫線を引く範囲を取得
        Dim sResultRange As String
        sResultRange = "B2:" & Cells( _
                       .UsedRange.Item(.UsedRange.Count).Row, _
                       .UsedRange.Item(.UsedRange.Count).Column) _
                       .Address(0, 0)
        '罫線
        .Range(sResultRange).Borders(xlEdgeTop).LineStyle = xlContinuous
        .Range(sResultRange).Borders(xlEdgeBottom).LineStyle = xlContinuous
        .Range(sResultRange).Borders(xlEdgeLeft).LineStyle = xlContinuous
        .Range(sResultRange).Borders(xlEdgeRight).LineStyle = xlContinuous
        .Range(sResultRange).Borders(xlInsideHorizontal).LineStyle = xlContinuous
        .Range(sResultRange).Borders(xlInsideVertical).LineStyle = xlContinuous
    
        '文字の表示位置
        .Range(sResultRange).HorizontalAlignment = xlLeft
    
    End With

End Sub

 ■実行
   下記の2つのシートを比較します。
   ※値、数式、文字色と背景色、フォントのすべてのチェックをしています。

比較したシート1
比較したシート2

 ■実行結果
   B列:差異のあったセル
   C列:差異内容
   D、E列:両シートのセル情報
   F列:補足欄(フォントを選択している場合は、両セルに設定されているフォント名を表示)

シート比較の結果を一覧で表示


 ●設定シートの作成
入力用の設定シートを自動で作成してくれるコードです。
使う場合は、定数や共通で利用している関数があるため、上記で紹介しているコードと同じモジュール内にこのコードをコピーして使ってください。

'******************************************************************
' 設定シートの作成
'******************************************************************
Sub MakeSettingSheet()
    
    Dim sSetSht As String: sSetSht = "設定シート"
    
    If Not ChkExistSheet(ThisWorkbook, sSetSht) Then
        Sheets.Add After:=Sheets(1)
        ActiveSheet.Name = sSetSht
    Else
        Sheets(sSetSht).Cells.Clear
    End If
    
    
    ThisWorkbook.Activate
    With Sheets(sSetSht)
        
        .Range("B3:E3").Interior.Color = 13431550
        .Range("B4:C5").Interior.Color = 13431550
        .Range("B7:D7").Interior.Color = 13431550
        .Range("B8:B11").Interior.Color = 13431550
        
        
        .Range("A1") = "シート比較"
        .Range("B2") = "設定"
        .Range("B4") = "対象"
        .Range("C4") = "1"
        .Range("C5") = "2"
        .Range("D3") = "ブックのパス(フルパス)"
        .Range("E3") = "シート名"
        
        
        .Range("B7") = "比較内容"
        .Range("C7") = "設定"
        .Range("D7") = "備考"
        .Range("B8") = "値"
        .Range("B9") = "数式"
        .Range("E9") = "数式の比較は数式同士の比較"
        .Range("B10") = "文字色・背景色"
        .Range("B11") = "フォント"
        
        .Range("D8") = "1:比較する" & vbCrLf & "1以外: 比較しない"
        
        '罫線
        .Range("B3:E5").Borders(xlEdgeTop).LineStyle = xlContinuous
        .Range("B3:E5").Borders(xlEdgeBottom).LineStyle = xlContinuous
        .Range("B3:E5").Borders(xlEdgeLeft).LineStyle = xlContinuous
        .Range("B3:E5").Borders(xlEdgeRight).LineStyle = xlContinuous
        .Range("B3:E5").Borders(xlInsideHorizontal).LineStyle = xlContinuous
        .Range("B3:E5").Borders(xlInsideVertical).LineStyle = xlContinuous
        
        
        .Range("B7:D11").Borders(xlEdgeTop).LineStyle = xlContinuous
        .Range("B7:D11").Borders(xlEdgeBottom).LineStyle = xlContinuous
        .Range("B7:D11").Borders(xlEdgeLeft).LineStyle = xlContinuous
        .Range("B7:D11").Borders(xlEdgeRight).LineStyle = xlContinuous
        .Range("B7:D11").Borders(xlInsideHorizontal).LineStyle = xlContinuous
        .Range("B7:D11").Borders(xlInsideVertical).LineStyle = xlContinuous
        
        .Columns("B").ColumnWidth = 14.5
        .Columns("C").ColumnWidth = 5.25
        .Columns("D").ColumnWidth = 33.5
        .Columns("E").ColumnWidth = 14.75
        
        .Range("B3:C3").Merge
        .Range("B4:B5").Merge
        .Range("B4:B5").VerticalAlignment = xlTop
        .Range("D8:D11").Merge
        .Range("D8:D11").VerticalAlignment = xlTop
        .Rows.AutoFit
        .Cells.Font.Name = "BIZ UDゴシック"
        
        '初期値
        .Range("C8") = "1"
        .Range("C9") = "1"
        .Range("C10") = "0"
        .Range("C11") = "0"
    End With

End Sub