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

2

Mid の代わりに MidB() を使用します。MidB は少し高速です。他の解決策は、stringpointer を整数の配列にコピーすることです。例えば:

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

編集:

いくつかのパフォーマンス テストを行いましたが、上記の 2 つのコードの違いはごくわずかです。2 番目のコード ブロックは、最初のコード ブロックよりも約 1% 高速です。

編集2:

以前の編集は無視してください。コード 2 はコード 1 よりも約 50% 効率が低くなります。ただし、RDHS が示唆するように、コード 2 を調整して、CHR と ASC を行き来する代わりに値を比較しました。約 40 文字の入力文字列から開始する方が効率的です。長いです。入力文字列が長いほど、コード 3 のパフォーマンスが向上します。入力文字列の長さが 944640 文字の場合、コード 3 はコード 1 よりも 57% 高速です。

統計: 最初の列は入力文字列の長さ (文字単位)、2 番目の列はコード 2 と比較したコード 3 の効率です。ご覧のとおり、文字列の長さが 5 文字の場合、コード 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 に答える