字符处理——大小写转换编程思路扩展

2020-07-28 11:54:00 浏览数 (1)

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倍左右。

0 人点赞