@Andreas,请看这对代码。更复杂的代码仍然运行得更快,但是会发生一些奇怪的事情。我的意思是,如果您在保存后运行每个代码(以某种方式刷新应用程序/VBA/其他...),则运行时间最短。然后,在每对运行之后添加一些额外的秒数(至少是毫秒)。因此,请尝试下一段代码并确认它们在您的安装中的行为相同。
我在 8700 行范围内测试了这两个代码,搜索字符串出现了 1216 次:
Sub Macro1Simple()
Dim i As Long, j As Long', dTime As Double
j = Range("A" & rows.count).End(xlUp).row 'changed the way of calculation, for the case of inserted rows existence.
On Error Resume Next
Range("A1:A" & j).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
j = Range("A" & rows.count).End(xlUp).row
'dTime = MicroTimer 'to measure duration
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
For i = j To 1 Step -1
If Range("A" & i) = "Testword" Then
Range("A" & i + 1).Insert
End If
Next i
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
'MsgBox (MicroTimer - dTime) * 1000 & " [ms]"
'Refresh
End Sub
复杂的版本:
Sub Macro1_Complicated()
Dim i As Long, j As Long, rngIns As Range, arrRng() As Range', dTime As Double
j = Range("A" & rows.count).End(xlUp).row 'it will work even with gaps in A:A column
On Error Resume Next
Range("A1:A" & j).SpecialCells(xlCellTypeBlanks).EntireRow.Delete: ' Stop
On Error GoTo 0
j = Range("A" & rows.count).End(xlUp).row
'dTime = MicroTimer 'to measure duration
For i = 1 To j
If Range("A" & i) = "Testword" Then
If rngIns Is Nothing Then
Set rngIns = Range("A" & i + 1)
Else
Set rngIns = Union(rngIns, Range("A" & i + 1))
End If
End If
Next i
If Not rngIns Is Nothing Then
If InStr(rngIns.Address(0, 0), ":") > 0 Then _
arrRng = makeDiscontNoLimit(rngIns)
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
For i = 0 To UBound(arrRng)
arrRng(i).EntireRow.Insert
Next i
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End If
'MsgBox (MicroTimer - dTime) * 1000 & " [ms]"
'Refresh
End Sub
Function makeDiscontNoLimit(rng As Range) As Variant
Dim a As Range, c As Range, strAddress As String, strAddr() As Range, i As Long, k As Long
Dim arNo As Long
ReDim strAddr(100)
For Each a In rng.Areas
If a.cells.count = 1 Then
strAddress = strAddress & a.Address(0, 0) & ","
If Len(strAddress) >= 256 Then
For i = Len(strAddress) - 1 To 1 Step -1
If Mid(strAddress, i, 1) = "," Then
Set strAddr(k) = Range(left(strAddress, i - 1)): k = k + 1
strAddress = Mid(strAddress, i + 1, Len(strAddress) - i): Exit For
End If
Next i
End If
Else
For Each c In a.cells
strAddress = strAddress & c.Address(0, 0) & ","
If Len(strAddress) >= 256 Then
For i = Len(strAddress) - 1 To 1 Step -1
If Mid(strAddress, i, 1) = "," Then
Set strAddr(k) = Range(left(strAddress, i - 1)): k = k + 1
strAddress = Mid(strAddress, i + 1, Len(strAddress) - i): Exit For
End If
Next i
End If
Next c
End If
Next a
If Not strAddr(0) Is Nothing Then
Set strAddr(k) = Range(left(strAddress, Len(strAddress) - 1))
ReDim Preserve strAddr(k)
makeDiscontNoLimit = strAddr: Exit Function
Else
Set strAddr(0) = Range(left(strAddress, Len(strAddress) - 1))
ReDim Preserve strAddr(0)
makeDiscontNoLimit = strAddr
End If
End Function
我可以创建一个函数来处理将(有限地址)范围放入数组中的重复部分,但我只想看到它在大范围内工作。
所以,为了避免每次运行后持续时间增加,我尝试了Refresh,但没有任何结果。你能想出一种方法让 VBA 在所有运行中都以相同的效率运行吗?
我使用 API getFrequency 结合 getTickCount 来测量时间。但我认为这不是时间问题。我没有放置API函数和必要的Sub,让你使用你的测量方式......