1、简单实现
前面我们实现了首字母大写、转换大写、转换小写3个功能,如果再实现一个大小写互换,有了前面的基础,实现起来应该没什么大问题:
代码语言:javascript复制Function FUpperLowerSwap(str As String) As String
Dim i As Long
Dim tmp As String
For i = 1 To VBA.Len(str)
tmp = VBA.Mid$(str, i, 1)
If tmp >= "a" And tmp <= "z" Then
tmp = VBA.UCase$(tmp)
Mid(str, i, 1) = tmp
ElseIf tmp >= "A" And tmp <= "Z" Then
tmp = VBA.LCase$(tmp)
Mid(str, i, 1) = tmp
End If
Next
FUpperLowerSwap = str
End Function
注意这里的Mid(str, i, 1) = tmp,里面的Mid是一个语句,不是字符串处理函数。功能是替换str中的字符。
实现了FUpperLowerSwap函数,我们只要调用这个函数就可以实现字符串中的字母大小写互换了。
2、思路扩展
函数里面主要是通过判断字符是否是小写字符或者是否是大写字符,然后进行转换,在这里这个功能比较简单,只需要两个If判断就可以。如果是要实现一个更复杂的功能,需要判断的东西更多,那么只能不停的增加If判断。
这样不但代码看起来混乱、复杂,而且一旦要处理的数据量太多,程序效率也会很低。
这里我们介绍一种比较常用的编程思路,使用数组来减少If的使用。
通过前面的了解,我们知道字母都是ASCII编码的,数字不会超过255,所以,我们首先可以使用一个下标是0-255的数组,分别对应ASCII编码的字符,那么字母自然也能够和数组一一对应。
数组记录什么呢?
我们这里是希望能够实现字母的大小写转换,所以需要记录的就是字符要进行转换的时候,需要去做什么。
根据前面提到过的大小写字母相差编码固定的知识,我们使用数组记录的就是这个需要增加的数字(减少的时候就是负数)。
而为了功能的更加完整,我们记录一个字符转换为大写、转换为小写、大小写转换3个数据,这个时候使用自定义的结构体就非常合适了:
代码语言:javascript复制Private Type Letter
'转换为大写需要增加的数字,可以是负数
ToUpper As Integer
'转换为小写需要增加的数字,可以是负数
ToLower As Integer
'转换需要增加的数字,可以是负数
Change As Integer
End Type
然后是要初始化:
代码语言:javascript复制Private Function InitLetters() As Letter()
Dim ret() As Letter
'ASCII字符不会超过255
ReDim ret(&HFF) As Letter
Dim i As Long
'记录小写字母需要转换的时候,应该增加的数字
For i = VBA.Asc("a") To VBA.Asc("z")
ret(i).ToUpper = VBA.Asc("A") - VBA.Asc("a")
ret(i).Change = ret(i).ToUpper
Next
'记录大写字母需要转换的时候,应该增加的数字
For i = VBA.Asc("A") To VBA.Asc("Z")
ret(i).ToLower = VBA.Asc("a") - VBA.Asc("A")
ret(i).Change = ret(i).ToLower
Next
'其他的字符都不需要初始化,默认为0即可
InitLetters = ret
End Function
在这个基础上,来实现FUpperLowerSwap函数,因为转换方式有3种,这里再使用枚举来定义:
代码语言:javascript复制Private Enum EChange
Upper
Lower
Change
End Enum
函数实现:
代码语言:javascript复制Private Function ToUpperLowerOrChange(str As String, ls() As Letter, C As EChange) As String
Dim i As Long
Dim b() As Byte
'String转换为byte来处理
b = str
'VBA使用的是Unicode编码,每个字符占用2个字节
For i = 0 To UBound(b) - 1 Step 2
'字符低位在前面,高位在后面,所以如果是ASCII字符的话,高位就是0
If b(i 1) = 0 Then
'这里不需要再判断是否是字母来,因为未初始化的ASCII字符转换的时候都是增加0,不会影响
Select Case C
Case EChange.Upper
b(i) = b(i) ls(b(i)).ToUpper
Case EChange.Lower
b(i) = b(i) ls(b(i)).ToLower
Case EChange.Change
b(i) = b(i) ls(b(i)).Change
End Select
End If
Next
ToUpperLowerOrChange = b
End Function
主函数再调用:
代码语言:javascript复制Sub UpperLowerSwap()
Dim rng As Range, selectRng As Range
Dim ls() As Letter
'确保选中的是单元格
If TypeName(Selection) = "Range" Then
Set selectRng = Selection
ls = InitLetters()
For Each rng In selectRng
rng.Value = ToUpperLowerOrChange(VBA.CStr(rng.Value), ls, EChange.Change)
Next rng
End If
Set rng = Nothing
Set selectRng = Nothing
End Sub
3、性能测试
代码语言:javascript复制Sub testletter()
Dim strs(500000) As String
Dim ls() As Letter
Dim t As Double
Dim i As Long
For i = 0 To UBound(strs)
strs(i) = "abABalsdfasSLDFJGOAEIsl中文..asdf1.,..,msfi"
Next
t = VBA.Timer
Debug.Print "扩展方法:"
Debug.Print "开始时间:", t
ls = InitLetters()
For i = 0 To UBound(strs)
ToUpperLowerOrChange strs(i), ls, Change
Next
Debug.Print "结束时间:", VBA.Timer
Debug.Print "使用时间:", VBA.Timer - t
Debug.Print "————————————————————————————"
t = VBA.Timer
Debug.Print "普通方法:"
Debug.Print "开始时间:", t
For i = 0 To UBound(strs)
FUpperLowerSwap strs(i)
Next
Debug.Print "结束时间:", VBA.Timer
Debug.Print "使用时间:", VBA.Timer - t
End Sub
本人电脑测试结果:
代码语言:javascript复制扩展方法:
开始时间: 36800.1328125
结束时间: 36801.96
使用时间: 1.828125
————————————————————————————
普通方法:
开始时间: 36801.9609375
结束时间: 36810.26
使用时间: 8.30078125
50万个字符串,1.8秒和8.3秒,时间差异大约在4倍左右。