学习Excel技术,关注微信公众号:
excelperfect
字符串处理会使VBA变慢。
假设想要找到字符串中第一个大写字母的位置,可以使用数组公式:
代码语言:javascript复制=MATCH(TRUE,ISERR(FIND(MID(A1,ROW($1:$255),1),LOWER(A1))),0)
如果有很多行,要查找每行字符串第一个大写字母的位置,则使用数组公式会花费不少时间。
如果编写用户自定义函数,则会更快些。代码如下:
代码语言:javascript复制Function FirstCap2(Cell As Range)
For FirstCap2 = 1 To Len(Cell.Value)
If Mid(Cell.Value, FirstCap2, 1) Like"[A-Z]" Then
Exit For
End If
Next FirstCap2
End Function
代码使用Mid遍历字符串,使用LIKE依次检查每个字符是否为大写字母A到大写字母Z之一。
稍微修改一下代码,让其运行更快:
代码语言:javascript复制Function FirstCap3(Rng As Range)
Dim theString As String
theString = Rng.Value2
For FirstCap3 = 1 To Len(theString)
If Mid$(theString, FirstCap3, 1) Like"[A-Z]" Then
Exit For
End If
Next FirstCap3
End Function
将代码更改为将字符串从单元格中仅取出一次,并使用Mid$函数而不是Mid函数。所有的VBA字符串处理函数都有2个版本:不带后缀$使用变体参数的版本,和带有$后缀的只能处理字符串参数的版本,后者速度更快。
但是,也许使用LIKE还是慢?尝试比较字符串的小写版本,并在字符不匹配时停止:
代码语言:javascript复制Function FirstCap4(strInp AsString) As Long
Dim tmp As String
Dim i As Long
Dim pos As Long
tmp = LCase$(strInp)
pos = -1
For i = 1 To Len(tmp)
If Mid$(tmp, i, 1) <>Mid$(strInp, i, 1) Then
pos = i
Exit For
End If
Next
FirstCap4 = pos
End Function
但这个版本比前一个版本更慢!将Byte数组与字符串一起使用是VBA不为人知的秘密之一,当需要依次检查每个字符时,它通常是处理字符串的一种有效方法。
代码语言:javascript复制Function FirstCap5(theRange AsRange) As Long
Dim aByte() As Byte
Dim j As Long
FirstCap5 = -1
aByte = theRange.Value2
For j = 0 To UBound(aByte, 1) Step 2
If aByte(j) < 91 Then
If aByte(j) > 64 Then
FirstCap5 = (j 2) / 2
Exit For
End If
End If
Next j
End Function
这个版本的自定义函数更快。代码首先创建一个Byte类型的数组,然后将字符串赋给该数组。字符串中的每个字符都有2个字节,英文大写字符的ANSI编号是65到90,因此可以循环这个字节数组,间隔查看其中的字节,并直接对字符进行数字测试,看它是否为大写。
Byte数组另一个令人惊讶的特点是可以直接赋值字节数组到字符串:
Dim str1 as string
str1=aByte
正如在上一篇文章中所讨论的,数组公式更快。因此,给出该用户定义函数的数组公式版本:
代码语言:javascript复制Function AFirstCap(theRange AsRange) As Variant
Dim aByte() As Byte
Dim j As Long
Dim L As Long
Dim vRange As Variant
Dim jAnsa() As Long
Dim NumCells As Long
vRange = theRange.Value2
NumCells = UBound(vRange, 1)
ReDim jAnsa(NumCells - 1, 0)
For L = 0 To NumCells - 1
jAnsa(L, 0) = -1
aByte = vRange(L 1, 1)
For j = 0 To UBound(aByte, 1) Step 2
If aByte(j) < 91 Then
If aByte(j) > 64 Then
jAnsa(L, 0) = (j 2) / 2
Exit For
End If
End If
Next j
Next L
AFirstCap = jAnsa
End Function
小结:在字符串处理中,需要检查或操作很多单个字符时,使用字节数组是一个很好的解决方案。