1、简单实现
前面我们实现了首字母大写、转换大写、转换小写3个功能,如果再实现一个大小写互换,有了前面的基础,实现起来应该没什么大问题:
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 = strEnd Function
注意这里的Mid(str, i, 1) = tmp,里面的Mid是一个语句,不是字符串处理函数。功能是替换str中的字符。
实现了FUpperLowerSwap函数,我们只要调用这个函数就可以实现字符串中的字母大小写互换了。
2、思路扩展
函数里面主要是通过判断字符是否是小写字符或者是否是大写字符,然后进行转换,在这里这个功能比较简单,只需要两个If判断就可以。如果是要实现一个更复杂的功能,需要判断的东西更多,那么只能不停的增加If判断。
这样不但代码看起来混乱、复杂,而且一旦要处理的数据量太多,程序效率也会很低。
这里我们介绍一种比较常用的编程思路,使用数组来减少If的使用。
通过前面的了解,我们知道字母都是ASCII编码的,数字不会超过255,所以,我们首先可以使用一个下标是0-255的数组,分别对应ASCII编码的字符,那么字母自然也能够和数组一一对应。
数组记录什么呢?
我们这里是希望能够实现字母的大小写转换,所以需要记录的就是字符要进行转换的时候,需要去做什么。
根据前面提到过的大小写字母相差编码固定的知识,我们使用数组记录的就是这个需要增加的数字(减少的时候就是负数)。
而为了功能的更加完整,我们记录一个字符转换为大写、转换为小写、大小写转换3个数据,这个时候使用自定义的结构体就非常合适了:
Private Type Letter '转换为大写需要增加的数字,可以是负数 ToUpper As Integer '转换为小写需要增加的数字,可以是负数 ToLower As Integer '转换需要增加的数字,可以是负数 Change As IntegerEnd Type
然后是要初始化:
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 = retEnd Function
在这个基础上,来实现FUpperLowerSwap函数,因为转换方式有3种,这里再使用枚举来定义:
Private Enum EChange Upper Lower ChangeEnd Enum
函数实现:
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 = bEnd Function
主函数再调用:
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 = NothingEnd Sub
3、性能测试
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 - tEnd Sub
本人电脑测试结果:
扩展方法:开始时间: 36800.1328125 结束时间: 36801.96 使用时间: 1.828125 ————————————————————————————普通方法:开始时间: 36801.9609375 结束时间: 36810.26 使用时间: 8.30078125
50万个字符串,1.8秒和8.3秒,时间差异大约在4倍左右。