比较两个工作表中的单元格并更快地突出显示差异

问题描述 投票:0回答:3

我正在尝试比较两个工作表并突出显示更改。这两个工作表是定期更新的同一数据集的不同版本,我需要跟踪所做的更改。对于修改的值和新添加的值,应分别突出显示更改(单元格颜色和用户预定义的字体颜色)。

我的代码适用于 100 行的小样本,但原始文件有约 7000 行,并且需要很长时间才能运行整个数据集的代码。

我添加了一个进度条以获得更好的用户界面,因为代码需要一些时间才能运行。

Sub Highlight()

    Dim DataRange As Range
    Dim SelCell As Range
    Dim CurVer As String
    Dim CompVer As String
    Dim IntColMod As Long
    Dim IntColAdd As Long
    Dim FontColMod As Long
    Dim FontColAdd As Long
    Dim ModCellCount As Long
    Dim AddCellCount As Long

    'Pre-defined highlight format
    IntColMod = Worksheets("Version recon").Range("Modified_Value_Format").Interior.Color
    FontColMod = Worksheets("Version recon").Range("Modified_Value_Format").Font.Color
    IntColAdd = Worksheets("Version recon").Range("Added_Value_Format").Interior.Color
    FontColAdd = Worksheets("Version recon").Range("Added_Value_Format").Font.Color
    ModCellCount = 0
    AddCellCount = 0
    
    CurVer = Worksheets("Version recon").Range("Current_Version").Value
    CompVer = Worksheets("Version recon").Range("Compare_Version").Value
    'Debug.Print CurVer
    'Debug.Print CompVer

    Worksheets(CurVer).Activate
    Worksheets(CurVer).Unprotect
    Set DataRange = ActiveCell.CurrentRegion
    'Debug.Print DataRange.Address
    
    Dim CellCount As Long
    CellCount = DataRange.Cells.Count
    'Debug.Print CellCount

    Code_Progress_Bar.Show
    Dim i As Long
    i = 1
     
    For Each SelCell In DataRange

        If SelCell.Text <> Worksheets(CompVer).Range(SelCell.Address).Text And IsEmpty(Worksheets(CompVer).Range(SelCell.Address).Value) Then
            Worksheets(CurVer).Range(SelCell.Address).Interior.Color = IntColAdd
            Worksheets(CurVer).Range(SelCell.Address).Font.Color = FontColAdd
            AddCellCount = AddCellCount + 1
            Debug.Print SelCell.Address

        ElseIf SelCell.Text <> Worksheets(CompVer).Range(SelCell.Address).Text Then
            Worksheets(CurVer).Range(SelCell.Address).Interior.Color = IntColMod
            Worksheets(CurVer).Range(SelCell.Address).Font.Color = FontColMod
            ModCellCount = ModCellCount + 1
            Debug.Print SelCell.Address

        End If

        DoEvents
        Code_Progress_Bar.Label2.Width = Code_Progress_Bar.Label1.Width * i / CellCount
        Code_Progress_Bar.Label3.Caption = Format(i / CellCount * 100, "#.0") & "% completed."
        i = i + 1
     
    Next SelCell

    Unload Code_Progress_Bar
    Beep

    MsgBox "All changes are highlighted in Tab: " & CurVer, , "Code run completed"
    
    Worksheets(CurVer).Protect
    ActiveWorkbook.Sheets("Version Recon").Range("ModifiedCellCount").Value = ModCellCount
    ActiveWorkbook.Sheets("Version Recon").Range("NewlyAddedCellCount").Value = AddCellCount
    'ActiveWorkbook.Sheets("Version Recon").Range("Current_Version").Value = SheetRename

End Sub
excel vba performance
3个回答
1
投票
Option Explicit

Sub Highlight()
    
    Dim CurVer As String, CompVer As String
    Dim IntColMod As Long, IntColAdd As Long
    Dim FontColMod As Long, FontColAdd As Long
    Dim ModCellCount As Long, AddCellCount As Long
    Dim t0 As Single: t0 = Timer
    
    ModCellCount = 0
    AddCellCount = 0
    
    'Pre-defined highlight format
    With Worksheets("Version recon")
        IntColMod = .Range("Modified_Value_Format").Interior.Color
        FontColMod = .Range("Modified_Value_Format").Font.Color
        IntColAdd = .Range("Added_Value_Format").Interior.Color
        FontColAdd = .Range("Added_Value_Format").Font.Color
        
        CurVer = .Range("Current_Version").Value
        CompVer = .Range("Compare_Version").Value
    End With
   
    ' arrays to compare values
    Dim arCur, arComp, sAddr As String, i As Long, j As Long
    Dim cel As Range, rng0 As Range, rngAdd As Range, rngMod As Range
    With Worksheets(CurVer)
        .Activate
        .Unprotect
        sAddr = .UsedRange.Address
        Set rng0 = .UsedRange.Cells(1, 1) ' top left
        arCur = .Range(sAddr).Value
        'Debug.Print sAddr
    End With
    arComp = Worksheets(CompVer).Range(sAddr).Value
    
    For i = 1 To UBound(arCur)
        For j = 1 To UBound(arCur, 2)
           ' compare
           If IsError(arComp(i, j)) Then arComp(i, j) = "#N/A"
           If IsError(arCur(i, j)) Then arCur(i, j) = "#N/A"

           If arComp(i, j) <> arCur(i, j) Then
              Set cel = rng0.Offset(i - 1, j - 1)
              ' add or mod
              If Len(arComp(i, j)) = 0 Then
                 If rngAdd Is Nothing Then
                     Set rngAdd = cel
                 Else
                     Set rngAdd = Union(rngAdd, cel)
                 End If
                 AddCellCount = AddCellCount + 1
              Else
                 If rngMod Is Nothing Then
                     Set rngMod = cel
                 Else
                     Set rngMod = Union(rngMod, cel)
                 End If
                 ModCellCount = ModCellCount + 1
              End If
           End If
        Next
    Next
    
    ' color adds
    If Not rngAdd Is Nothing Then
        rngAdd.Interior.Color = IntColAdd
        rngAdd.Font.Color = FontColAdd
        Debug.Print "Add", AddCellCount, rngAdd.Address
    End If
    
    ' color mods
    If Not rngMod Is Nothing Then
        rngMod.Interior.Color = IntColMod
        rngMod.Font.Color = FontColMod
        Debug.Print "Mod", ModCellCount, rngMod.Address
    End If
    
    MsgBox "All changes are highlighted in Tab: " & CurVer, vbInformation, _
    "Code run in " & Format(Timer - t0, "0.0 secs")
    
    Worksheets(CurVer).Protect
    With ActiveWorkbook.Sheets("Version Recon")
        .Range("ModifiedCellCount").Value = ModCellCount
        .Range("NewlyAddedCellCount").Value = AddCellCount
        '.Range("Current_Version").Value = SheetRename ??
    End With
End Sub

1
投票

将数据加载到数组中并进行比较是一种更有效的方法。您甚至可能不再需要进度条。

注意: 由于缺乏示例数据,代码未经测试。

Option Explicit

Sub Highlight()
    Dim CurVer As String
    Dim CompVer As String
    Dim IntColMod As Long
    Dim IntColAdd As Long
    Dim FontColMod As Long
    Dim FontColAdd As Long
    Dim verSht As Worksheet, currSht As Worksheet, CompSht As Worksheet
    Set verSht = Worksheets("Version recon")
    IntColMod = verSht.Range("Modified_Value_Format").Interior.Color
    FontColMod = verSht.Range("Modified_Value_Format").Font.Color
    IntColAdd = verSht.Range("Added_Value_Format").Interior.Color
    FontColAdd = verSht.Range("Added_Value_Format").Font.Color
    CurVer = verSht.Range("Current_Version").Value
    CompVer = verSht.Range("Compare_Version").Value
    Set currSht = Worksheets(CurVer)
    Set CompSht = Worksheets(CompVer)
    currSht.Unprotect
    Dim arrCurr, arrComp, ltRow As Long, ltCol As Long
    With currSht.UsedRange
        ' get row# and col# of the top-left cell (table may not start from A1)
        ltRow = .Cells(1).Row
        ltCol = .Cells(1).Column
        ' load data into array
        arrCurr = .Value
        arrComp = CompSht.Range(.Address).Value
    End With
    Dim r As Long, c As Long, addRng As Range, modRng As Range
    ' loop through cells
    For r = 1 To UBound(arrCurr)
        For c = 1 To UBound(arrCurr, 2)
            ' *** Update ***
            If CStr(arrCurr(r, c)) <> CStr(arrComp(r, c)) Then ' found different
                If Len(CStr(arrComp(r, c))) = 0 Then ' new added content
                    MergeRng addRng, currSht.Cells(r + ltRow - 1, c + lrCol - 1)
                Else ' modify
                    MergeRng modRng, currSht.Cells(r + ltRow - 1, c + lrCol - 1)
                End If
            End If
        Next
    Next
    ' apply formatting
    If Not addRng Is Nothing Then
        With addRng
            .Interior.Color = IntColAdd
            .Font.Color = FontColAdd
            verSht.Range("NewlyAddedCellCount").Value = .Cells.Count
        End With
    End If
    If Not modRng Is Nothing Then
        With modRng
            .Interior.Color = IntColMod
            .Font.Color = FontColMod
            verSht.Range("ModifiedCellCount").Value = .Cells.Count
        End With
    End If
    MsgBox "All changes are highlighted in Tab: " & CurVer, , "Code run completed"
    Worksheets(CurVer).Protect
End Sub
' helper UDF to merge two Range objects
Function MergeRng(ByRef RngAll As Range, ByRef RngSub As Range) As Range
    If RngAll Is Nothing Then
        Set RngAll = RngSub
    ElseIf Not RngSub Is Nothing Then
        Set RngAll = Application.Union(RngAll, RngSub)
    End If
    Set MergeRng = RngAll
End Function


0
投票

添加条件格式规则通常比单独格式化多个单元格要快。 但您可能需要考虑在审核后删除条件格式。

Option Explicit

Function GetCurrentWorksheet() As Worksheet
    Dim Name As String
    Name = Worksheets("Version recon").Range("Current_Version").Value
    Set GetCurrentWorksheet = Worksheets(Name)
End Function

Function GetCompareWorksheet() As Worksheet
    Dim Name As String
    Name = Worksheets("Version recon").Range("Compare_Version").Value
    Set GetCompareWorksheet = Worksheets(Name)
End Function

Sub AddConditionalFormattingRules()
    Dim t As Double: t = Timer
    Dim wsCurrentWorksheet As Worksheet
    Dim wsCompareWorksheet As Worksheet
    Dim Target As Range
    Dim CurrentSheetName As String
    Dim CompareSheetName As String
    Dim StartCellAddress As String

    ' Define worksheets
    Set wsCurrentWorksheet = GetCurrentWorksheet
    Set wsCompareWorksheet = GetCompareWorksheet
    CurrentSheetName = wsCurrentWorksheet.Name
    CompareSheetName = wsCompareWorksheet.Name

    ' Define the range in the "Compare" sheet for conditional formatting
    With wsCompareWorksheet
        Set Target = Union(.UsedRange, .Range(wsCurrentWorksheet.UsedRange.Address))
    End With

    ' Get the address of the first cell in the target range
    StartCellAddress = Target.Cells(1, 1).Address(RowAbsolute:=False, ColumnAbsolute:=False)

    ' Clear existing conditional formatting
    Target.FormatConditions.Delete
    
    ' Rule 1: If the cell in the current sheet is empty and the corresponding cell in the compare sheet is not empty, apply "Neutral"
    With Target.FormatConditions.Add(Type:=xlExpression, Formula1:="=AND(ISBLANK('" & CurrentSheetName & "'!" & StartCellAddress & "),NOT(ISBLANK('" & CompareSheetName & "'!" & StartCellAddress & ")))")
        .Interior.Color = Worksheets("Version recon").Range("Added_Value_Format").Interior.Color
        .Font.Color = Worksheets("Version recon").Range("Added_Value_Format").Font.Color
    End With
    
    ' Rule 2: If the cell in the current sheet is not empty and differs from the corresponding cell in the compare sheet, apply "Bad"
    With Target.FormatConditions.Add(Type:=xlExpression, Formula1:="=AND(NOT(ISBLANK('" & CurrentSheetName & "'!" & StartCellAddress & ")),'" & CurrentSheetName & "'!" & StartCellAddress & " <> '" & CompareSheetName & "'!" & StartCellAddress & ")")
        .Interior.Color = Worksheets("Version recon").Range("Modified_Value_Format").Interior.Color
        .Font.Color = Worksheets("Version recon").Range("Modified_Value_Format").Font.Color
    End With
    
    Debug.Print Timer - t

    ' MsgBox "Conditional formatting rules applied.", vbInformation
End Sub
© www.soinside.com 2019 - 2024. All rights reserved.