3

对于某些协议测试,我需要随机化大量字符串中每个字符的大小写。字符串是命令,由我的应用程序创建,将通过 winsock 控件发送到客户端。

由于它涉及很多字符串,我希望每个部分都尽可能快。

现在我有:

Private Function RandomCaps(strText As String) As String
  Dim lngChar As Long
  Dim strLower As String, strUpper As String
  Dim strRandom As String
  strRandom = ""
  strLower = LCase$(strText)
  strUpper = UCase$(strText)
  For lngChar = 1 To Len(strText)
    If Int(2 * Rnd) = 0 Then
      strRandom = strRandom & Mid$(strLower, lngChar, 1)
    Else
      strRandom = strRandom & Mid$(strUpper, lngChar, 1)
    End If
  Next lngChar
  RandomCaps = strRandom
End Function

这很简单,但可能不是最快的方法。

我能做些什么来提高它的速度?

4

3 回答 3

3

不要将字符串连接在一起,而是使用Mid就地更改字符串:

Private Function RandomCaps(s As String) As String
    Dim uc As String
    Dim i As Long

    RandomCaps = LCase$(s)
    uc = UCase$(s)
    For i = 1 To Len(s) 
        If Rnd < 0.5 Then
            Mid(RandomCaps, i, 1) = Mid(uc, i, 1)
        End If
    Next i
End Function

您可以尝试使用MidB,但它几乎没有任何区别 - 因为它适用于单个字节,如果您不知道 VB6 如何存储字符串,您会遇到一些令人讨厌的惊喜。

于 2013-10-08T15:43:46.727 回答
2

使用 MidB() 代替 Mid。MidB 快一点。另一种解决方案可能是将字符串指针复制到整数数组中。例如:

Public Type TUDTPtr
    pSA        As Long
    Reserved   As Long ' z.B. für vbVarType oder IRecordInfo
    cDims      As Integer
    fFeatures  As Integer
    cbElements As Long
    cLocks     As Long
    pvData     As Long
    cElements  As Long
    lLBound    As Long
End Type

Public Type TCharPointer
    pudt    As TUDTPtr
    Chars() As Integer
End Type

Public Enum SAFeature
    FADF_AUTO = &H1
    FADF_STATIC = &H2
    FADF_EMBEDDED = &H4

    FADF_FIXEDSIZE = &H10
    FADF_RECORD = &H20
    FADF_HAVEIID = &H40
    FADF_HAVEVARTYPE = &H80

    FADF_BSTR = &H100
    FADF_UNKNOWN = &H200
    FADF_DISPATCH = &H400
    FADF_VARIANT = &H800
    FADF_RESERVED = &HF008
End Enum

Public Declare Sub RtlMoveMemory Lib "kernel32" ( _
                   ByRef pDst As Any, _
                   ByRef pSrc As Any, _
                   ByVal bLength As Long)

Public Declare Sub RtlZeroMemory Lib "kernel32" ( _
                   ByRef pDst As Any, _
                   ByVal bLength As Long)

Public Declare Function ArrPtr Lib "msvbvm60" _
                        Alias "VarPtr" ( _
                        ByRef pArr() As Any) As Long

Public Sub New_UDTPtr(ByRef this As TUDTPtr, _
                      ByVal Feature As SAFeature, _
                      ByVal bytesPerElement As Long, _
                      Optional ByVal CountElements As Long = 1, _
                      Optional ByVal lLBound As Long = 0)
    With this
        .pSA = VarPtr(.cDims)
        .cDims = 1
        .cbElements = bytesPerElement
        .fFeatures = CInt(Feature)
        .cElements = CountElements
        .lLBound = lLBound
    End With
End Sub
Public Sub New_CharPointer(ByRef this As TCharPointer, ByRef StrVal As String)
    With this
        Call New_UDTPtr(.pudt, FADF_AUTO Or FADF_FIXEDSIZE, 2, Len(StrVal), 1)
        With .pudt
            .pvData = StrPtr(StrVal)
        End With
        Call RtlMoveMemory(ByVal ArrPtr(.Chars), ByVal VarPtr(.pudt), 4)
    End With
End Sub

Public Sub DeleteCharPointer(ByRef this As TCharPointer)
    With this
        Call RtlZeroMemory(ByVal ArrPtr(.Chars), 4)
    End With
End Sub

您的函数可能如下所示:

Private Sub RandomCapsX(strText As String) 'As String
    Dim i As Long
    Dim p As TCharPointer: Call MCharPointer.New_CharPointer(p, strText)
    For i = 1 To p.pudt.cElements
        Select Case p.Chars(i)
        Case 65 To 90
            'Uppercase
            p.Chars(i) = p.Chars(i) + Int(2 * Rnd) * 32
        Case 97 To 122
            'lowercase
            p.Chars(i) = p.Chars(i) - Int(2 * Rnd) * 32
        End Select
    Next
    Call MCharPointer.DeleteCharPointer(p)
End Sub
于 2013-10-08T15:16:32.920 回答
1

要通过 RDHS 优化代码,您实际上不需要保留字符串的大写版本。我认为这是尽可能优化的。

代码 1:

Private Function RandomCaps(s As String) As String
    Dim i As Long
    RandomCaps = LCase$(s)
    For i = 1 To Len(s)
        If Rnd < 0.5 Then
            Mid(RandomCaps, i, 1) = UCase(Mid(RandomCaps, i, 1))
        End If
    Next i
End Function

上面的代码很好,但是,在非常大的字符串的情况下,您可能想试试这个(未测试性能与 RDHS 的代码):

代码 2:

Private Function RandomCaps(s As String) As String
    Dim b() As Byte
    b = StrConv(Text1.Text, vbFromUnicode)
    Dim i As Long
    For i = 0 To UBound(b) - 1
        If Rnd < 0.5 Then
            If UCase(Chr(b(i))) = Chr(b(i)) Then
               'original char is uppercase, make it lowercase
                b(i) = Asc(LCase(Chr(b(i))))
            Else
                'original char is lowercase, make it uppercase
                b(i) = Asc(UCase(Chr(b(i))))
            End If
        End If
    Next i
    RandomCaps = StrConv(b, vbUnicode)
End Function

编辑:

我做了一些性能测试,上面两个代码之间的差异可以忽略不计:第二个代码块只比第一个快 1%。

编辑2:

忽略我之前的编辑。代码 2 的效率比代码 1 低大约 50%。但是,正如 RDHS 建议的那样,我调整了代码 2 来比较值,而不是从 CHR 到 ASC 来回比较,从大约 40 个字符的输入字符串开始效率更高长。输入字符串越长,code 3 的性能越好。对于长度为 944640 个字符的输入字符串,代码 3 比代码 1 快 57%。

统计:第一列是输入字符串的长度(以字符为单位) 第二列是 Code 3 与 Code 2 相比的效率。如您所见,字符串长度为 5 个字符,Code 2 效率提高了 46%。从 40 左右的字符串长度开始,代码 3 变得越来越高效。

5 -46.80%

50 6.22%

100 21.50%

500 38.54%

1000 41.11%

10000 44.87%

100000 43.25%

1260000 43.02%

代码 3:

Private Function RandomCaps(s As String) As String
    Dim b() As Byte
    b = StrConv(Text1.Text, vbFromUnicode)
    Dim i As Long
    For i = 0 To UBound(b) - 1
        If Rnd < 0.5 Then
            If b(i) >= 64 And b(i) <= 90 Then
                'A to Z
                b(i) = b(i) + 32
            ElseIf b(i) >= 97 And b(i) <= 122 Then
                'a to z
                b(i) = b(i) - 32
            Else
                'everything else
            End If
        End If
    Next i
    RandomCaps = StrConv(b, vbUnicode)
End Function
于 2013-10-08T17:10:24.143 回答