programing

배열의 모든 구성원을 영숫자로 전환하는 가장 빠른 방법은 무엇입니까?

goodsources 2023. 8. 29. 20:30
반응형

배열의 모든 구성원을 영숫자로 전환하는 가장 빠른 방법은 무엇입니까?

최종 최종 결과:

아래의 결과가 문자열이 더 길면 바뀐 것인지 궁금합니다.동일한 컴퓨터에서 정확히 동일한 테스트를 실행했습니다. 각 셀에는 4자가 아닌 34자의 임의 문자열이 있었습니다.결과는 다음과 같습니다.

Comintern (Regexp):       136.1  ms  
brettdj (Regexp):         139.9  ms  
Slai (Regexp):            158.4  ms  
*Original Regex:          161.0  ms*    
Comintern (AN):           170.1  ms  
Comintern (Hash):         183.6  ms  
ThunderFrame:             232.9  ms    
*Original replace:        372.9  ms*  
*Original InStr:          478.1  ms*  
CallumDA33:              1218.1 ms

이것은 Regex의 속도를 보여줍니다. Regex.replace를 사용하는 모든 솔루션이 훨씬 더 빠르며, 가장 좋은 것은 Cominter의 구현입니다.

요약하면 문자열이 길면 배열을 사용하고 짧으면 클립보드를 사용합니다.확실하지 않은 경우 어레이를 사용하는 것이 최적의 결과이지만 짧은 문자열의 성능이 약간 저하될 수 있습니다.

최종 결과:

당신의 제안에 정말 감사드립니다, 분명히 저는 아직 배울 것이 많습니다.저는 어제 이 모든 것을 생각하고 있었기 때문에 집에서 모든 것을 모두 다시 하기로 했습니다.이것들을 30,000개의 네 개의 문자열에 각각 적용한 최종 결과입니다.

집에 있는 제 컴퓨터는 Intel i7 @ 3.6GHz, 8GB RAM, 64비트 Windows 10 및 Excel 2016입니다.백그라운드에서 프로세스를 실행한다는 점에서 이전과 유사한 조건이지만 테스트 내내 적극적으로 아무것도 하지 않습니다.

Original replace:  97.67  ms
Original InStr:    106.54 ms
Original Regex:    113.46 ms
ThunderFrame:      82.21  ms
Comintern (AN):    96.98  ms
Comintern (OR):    81.87  ms
Comintern (Hash):  101.18 ms
brettdj:           81.66  ms
CallumDA33:        201.64 ms
Slai:              68.38  ms

따라서 Slai의 답변은 일반적으로 구현하는 것이 가장 빠르다는 점에서 수락했지만, 실제 데이터와 비교하여 작업 중에 모두 다시 실행하여 이 답변이 여전히 작동하는지 확인하겠습니다.


원본 게시물:

엑셀에 부품 번호 목록이 있는 배열이 있습니다.예를 들어 어레이의 모든 구성원을 영숫자로 전환해야 합니다.

ABC123-001 -> ABC123001
ABC123/001 -> ABC123001
ABC123001  -> ABC123001

이것을 하는 가장 빠른 방법은 무엇입니까?

상황에 따라 부품 번호의 형태가 다를 수 있으므로 주어진 범위 내에서 가장 적합한 부품을 찾는 기능을 작성하고 있습니다.현재, 모든 것을 영숫자로 만드는 기능의 부분은 실행하는 데 약 50ms가 걸리는 반면, 나머지 기능은 총 30ms가 걸립니다.저도 엑셀을 사용하지 않을 수 없습니다.

제가 직접 몇 가지 작업을 수행했습니다(아래 답변 참조). 주요 문제는 어레이의 모든 요소를 하나씩 반복해서 살펴봐야 한다는 것입니다. 더 나은 방법이 있을까요?저도 테스트를 해본 적이 없기 때문에 개선에 대한 피드백을 주시면 감사하겠습니다.

여기 제가 지금까지 시도한 것이 있습니다.

MicroTimer를 사용하고 있으며 컴퓨터에 Intel i5 @2.5가 있습니다.GHz, 4GB RAM, 64비트 Windows 7.백그라운드에서 프로세스를 실행하고 있지만 실행되는 동안에는 다른 작업을 수행하지 않습니다.

다음 코드를 사용하여 30,000줄의 임의 기호를 만들었습니다.

=CHAR(RANDBETWEEN(1,60))&CHAR(RANDBETWEEN(48,57))&CHAR(RANDBETWEEN(37,140))&CHAR(RANDBETWEEN(37,140))

이(가) 60이기 때문에 첫 합니다.('='의 경우)char(61)그리고 우리는 엑셀이 이것을 공식으로 해석하는 것을 피하고 싶습니다.또한 두 번째 문자를 숫자로 지정하여 최소 하나의 영숫자 문자를 보장할 수 있습니다.)

사례를 기반으로 한 루프 사용.평균 시간: 175ms

게시물의 기능을 사용하여 범위를 배열에 로드하고 배열의 각 요소에 해당 기능을 적용한 후 다시 붙여넣습니다.코드:

Function AlphaNumericOnly(strSource As Variant) As String
    Dim i As Integer
    Dim strResult As String

    For i = 1 To Len(strSource)
        Select Case Asc(Mid(strSource, i, 1))
            Case 48 To 57, 65 To 90, 97 To 122: 'include 32 if you want to include space
                strResult = strResult & Mid(strSource, i, 1)
        End Select
    Next
    AlphaNumericOnly = strResult
End Function

Sub Replace()

    Dim inputSh As Worksheet
    Dim inputRng As Range
        Set inputSh = Sheets("Data")
        Set inputRng = inputSh.Range("A1:A30000")

    Dim outputSh As Worksheet
    Dim outputRng As Range
        Set outputSh = Sheets("Replace")
        Set outputRng = outputSh.Range("A1:A30000")

    Dim time1 As Double, time2 As Double
        time1 = MicroTimer

    Dim arr As Variant
        arr = inputRng

    Dim i As Integer
        For i = LBound(arr) To UBound(arr)
            arr(i, 1) = AlphaNumericOnly(arr(i, 1))
        Next i

    outputRng = arr

    time2 = MicroTimer

    Debug.Print (time2 - time1) * 1000

End Sub

InStr()을 사용하여 각 문자를 확인합니다.평균 시간: 201ms

유효한 값의 문자열을 정의합니다.배열 요소에 유효한 값이 표시되는지 하나씩 확인합니다.

Sub InStr()

    Dim inputSh As Worksheet
    Dim inputRng As Range
        Set inputSh = Sheets("Data")
        Set inputRng = inputSh.Range("A1:A30000")

    Dim outputSh As Worksheet
    Dim outputRng As Range
        Set outputSh = Sheets("InStr")
        Set outputRng = outputSh.Range("A1:A30000")

    Dim time1 As Double, time2 As Double
        time1 = MicroTimer

    Dim arr As Variant
        arr = inputRng

    Dim validValues As String
        validValues = "01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 'put numbers and capitals at the start as they are more likely'

    Dim i As Integer, j As Integer
    Dim result As String

        For i = LBound(arr) To UBound(arr)
        result = vbNullString
            For j = 1 To Len(arr(i, 1))
                If InStr(validValues, Mid(arr(i, 1), j, 1)) <> 0 Then
                    result = result & Mid(arr(i, 1), j, 1)
                End If
            Next j
        arr(i, 1) = result
        Next i

    outputRng = arr

    time2 = MicroTimer

    Debug.Print (time2 - time1) * 1000

End Sub

정규식 사용.배열을 바꿉니다.시간: 171ms

정규식을 정의하고 이를 사용하여 배열의 각 요소를 바꿉니다.

Sub Regex()

    Dim inputSh As Worksheet
    Dim inputRng As Range
        Set inputSh = Sheets("Data")
        Set inputRng = inputSh.Range("A1:A30000")

    Dim outputSh As Worksheet
    Dim outputRng As Range
        Set outputSh = Sheets("Regex")
        Set outputRng = outputSh.Range("A1:A30000")

    Dim time1 As Double, time2 As Double
        time1 = MicroTimer

    Dim arr As Variant
        arr = inputRng

    Dim objRegex As Object
        Set objRegex = CreateObject("vbscript.regexp")
        With objRegex
            .Global = True
            .ignorecase = True
            .Pattern = "[^\w]"
        End With

    Dim i As Integer
        For i = LBound(arr) To UBound(arr)
            arr(i, 1) = objRegex.Replace(arr(i, 1), vbNullString)
        Next i

    outputRng = arr

    time2 = MicroTimer

    Debug.Print (time2 - time1) * 1000

End Sub

편집:

@ThunderFrame - 당사의 부품 번호는 일반적으로 다음과 같은 형식으로 제공됩니다.

  • 모든 번호(예: 32523452)
  • 문자와 숫자의 혼합(예: AB324K234 또는 123H45645)
  • 영숫자가 아닌 문자로 연결된 문자와 숫자 혼합(예: ABC001-001, ABC001/001, 123/4557-121)

교체를 시작하기 전에 각 문자열에 regex.test를 사용하는 것에 대해 생각해 보았지만, 이것이 단순히 문자열을 복사한 다음 테스트할 수 있을지 확신할 수 없습니다. 이 경우 교체를 시작하는 것이 좋습니다.

@슬라이 - 링크 감사합니다 - 더 자세히 알아보겠습니다.

너무 많은 요인에 의존하기 때문에 이 방법이 더 빠를지는 모르겠지만 테스트해 볼 가치가 있을 수 있습니다.정규식입니다.각 값을 개별적으로 바꿉니다. 클립보드에서 복사된 범위 텍스트를 가져와 모든 값을 한 번에 바꿀 수 있습니다.:\w는 밑줄 및 유니코드 문자와도 일치하므로 정규식에서 보다 구체적으로 지정하면 더 빠르게 처리할 수 있습니다.

'[a1:b30000] = [{"ABC123-009",""}]: Dim t As Double: t = Timer ' used for testing

Dim r As Range, s As String
Set r = ThisWorkbook.Worksheets("Data").UsedRange.Resize(, 1) ' Data!A1:A30000
With New MSForms.DataObject ' needs reference to "Microsoft Forms 2.0 Object Library" or use a bit slower late binding - With CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
   r.Copy
   .GetFromClipboard
    Application.CutCopyMode = False
    s = .GetText
    .Clear ' optional - clear the clipboard if using Range.PasteSpecial instead of Worksheet.PasteSpecial "Text"

    With New RegExp ' needs reference to "Microsoft VBScript Regular Expressions 5.5" or use a bit slower late binding - With CreateObject("VBScript.RegExp")
        .Global = True
        '.IgnoreCase = False ' .IgnoreCase is False by default
        .Pattern = "[^0-9A-Za-z\r\n]+" ' because "[^\w\r\n]+" also matches _ and Unicode letters
        s = .Replace(s, vbNullString)
    End With

    .SetText s
    .PutInClipboard
End With

' about 70% of the time is spent here in pasting the data 
r(, 2).PasteSpecial 'xlPasteValues ' paste the text from clipboard in B1

'Debug.Print Timer - t

클립보드 오버헤드 때문에 값이 적을 경우 속도가 느리고 메모리가 필요하기 때문에 값이 많을 경우 속도가 느려질 수 있습니다.

이벤트를 비활성화하는 것은 제 테스트에서 차이가 없는 것 같았지만, 시도해 볼 가치가 있을지도 모릅니다.

매크로가 클립보드를 사용하는 동안 다른 응용프로그램이 클립보드를 사용할 가능성은 거의 없습니다.

조기 바인딩으로 인해 서로 다른 시스템에서 동일한 컴파일된 매크로를 실행하는 데 문제가 발생하는 경우 매크로 디컴파일러를 검색하거나 참조를 제거한 후 지연 바인딩으로 전환할 수 있습니다.

tl;dr - 정규식은 VBA 구현을 파괴합니다.만약 이것이 코드 챌린지라면, @brettj 또는 @Slai가 이겨야 합니다.

당신을 만들기 위한 많은 속임수들이 있습니다.AlphaNumericOnly빠른.

첫째, 문자열이 아닌 바이트 배열로 처리하여 대부분의 함수 호출을 제거할 수 있습니다. 그면에대모제거다니됩호출이러에 대한 됩니다.Mid$그리고.Asc이러한 기능은 매우 빠른 속도이지만, 통화 스택을 밀고 나가는 오버헤드를 추가합니다.그것은 수십만 번 이상의 반복입니다.

번째 는 두번째최사않것는입다니지용하를 사용하지 입니다.Case x To y구문을 사용할 수 있습니다.. - ▁like와 같은 같은 테스트로 컴파일하지 않습니다.Case = Condition >= x And Condition <= y실제로는 다음과 같은 조기 종료 조건을 가진 루프를 생성합니다.

Case = False
For i = x To y
    If Condition = i Then
        Case = True
    End If
Next

다시 말씀드리지만, 큰 성과를 거두지는 못했지만, 그것은 더해진 것입니다.세 번째 최적화는 데이터 집합에서 가장 가능성이 높은 적중 횟수에 대해 회로를 정렬하는 방식으로 검정을 정렬하는 것입니다.나는 아래의 예들을 대부분 대문자와 함께 주로 글자에 맞게 조정했습니다.당신은 다른 주문으로 더 잘할 수 있습니다.이 모든 것을 합치면 다음과 같은 것을 얻을 수 있습니다.

Public Function ByteAlphaNumeric(source As Variant) As String
    Dim chars() As Byte
    Dim outVal() As Byte
    chars = CStr(source)        'Load the array up.

    Dim bound As Long
    bound = UBound(chars)       'Size the outbound array.
    ReDim outVal(bound)

    Dim i As Long, pos As Long
    For i = 0 To bound Step 2   'Wide characters, only care about the ASCII range.
        Dim temp As Byte
        temp = chars(i)         'Pointer math isn't free. Cache it.
        Select Case True        'Order is important here.
            Case temp > 64 And temp < 91
                outVal(pos) = temp
                pos = pos + 2   'Advance the output pointer.
            Case temp < 48
            Case temp > 122
            Case temp > 96
                outVal(pos) = temp
                pos = pos + 2
            Case temp < 58
                outVal(pos) = temp
                pos = pos + 2
        End Select
    Next
    'This is likely the most expensive operation.
    ReDim Preserve outVal(pos)  'Trim the output array.
    ByteAlphaNumeric = outVal
End Function

어때요?아주 좋습니다.

Public Sub Benchmark()
    Dim starting As Single, i As Long, dummy As String, sample As Variant

    sample = GetRandomString

    starting = Timer
    For i = 1 To 1000000
        dummy = AlphaNumericOnlyOP(sample)
    Next i
    Debug.Print "OP's AlphaNumericOnly: ", Timer - starting

    starting = Timer
    For i = 1 To 1000000
        dummy = AlphaNumericOnlyThunderframe(sample)
    Next i
    Debug.Print "ThunderFrame's AlphaNumericOnly: ", Timer - starting

    starting = Timer
    For i = 1 To 1000000
        dummy = AlphaNumeric(sample)
    Next i
    Debug.Print "CallumDA33's AlphaNumeric: ", Timer - starting

    starting = Timer
    For i = 1 To 1000000
        dummy = ByteAlphaNumeric(sample)
    Next i
    Debug.Print "ByteAlphaNumeric: ", Timer - starting

    Dim cast As String
    cast = CStr(sample)
    starting = Timer
    For i = 1 To 1000000
        dummy = ByteAlphaNumericString(cast)
    Next i
    Debug.Print "ByteAlphaNumericString: ", Timer - starting

    Set stripper = Nothing
    starting = Timer
    For i = 1 To 1000000
        dummy = OptimizedRegex(sample)
    Next i
    Debug.Print "OptimizedRegex: ", Timer - starting

End Sub

Private Function GetRandomString() As Variant
    Dim chars(30) As Byte, i As Long
    Randomize
    For i = 0 To 30 Step 2
        chars(i) = Int(96 * Rnd + 32)
    Next i
    Dim temp As String
    temp = chars
    GetRandomString = CVar(temp)
End Function

15자 랜덤의 결과String:

OP`s AlphaNumericOnly:                     6.565918 
ThunderFrame`s AlphaNumericOnly:           3.617188 
CallumDA33`s AlphaNumeric:                23.518070 
ByteAlphaNumeric:                          2.354980

참고로, 함수로 변환하기 위해 사소한 것이 아닌 제출을 생략했습니다.2개의 테스트 - 2개의 테스트 - 를 할 수 .ByteAlphaNumericString는 그과정같습다니히확것▁the▁the와 정확히 같습니다.ByteAlphaNumeric기능, 하지만 그것은 필요합니다.String 대신 Variant깁스를 제거할 수 있습니다.그것은 사소한 것이 아닙니다.

ByteAlphaNumericString:                    2.226074

그리고 마지막으로, 이해하기 어려운 것은OptimizedRegex타이밍을 위해 @brettj의 ): function (function @코j드표시basically로태이교

Private stripper As RegExp  'Module level

Function OptimizedRegex(strSource As Variant) As String
    If stripper Is Nothing Then
        Set stripper = New RegExp
        With stripper
            .Global = True
            .Pattern = "[^0-9A-Za-z]"
        End With
    End If
    OptimizedRegex = stripper.Replace(strSource, vbNullString)
End Function
OptimizedRegex:                            1.094727 

편집: 보너스 구현!

해시 테이블 검색이 다음보다 빠를 수도 있다는 생각이 들었습니다.Select Case구조, 그래서 나는 그것을 사용하여 하나를 만들었습니다.Scripting.Dictionary:

Private hash As Scripting.Dictionary  'Module level

Function HashLookups(source As Variant) As String
    Dim chars() As Byte
    Dim outVal() As Byte

    chars = CStr(source)
    Dim bound As Long
    bound = UBound(chars)
    ReDim outVal(bound)

    Dim i As Long, pos As Long
    With hash
        For i = 0 To bound Step 2
            Dim temp As Byte
            temp = chars(i)
            If .Exists(temp) Then
                outVal(pos) = temp
                pos = pos + 2
            End If
        Next
    End With
    ReDim Preserve outVal(pos)
    HashLookups = outVal
End Function

Private Sub LoadHashTable()
    Set hash = New Scripting.Dictionary
    Dim i As Long
    For i = 48 To 57
        hash.Add i, vbNull
    Next
    For i = 65 To 90
        hash.Add i, vbNull
    Next
    For i = 97 To 122
        hash.Add i, vbNull
    Next
End Sub

'Test code:
    starting = Timer
    LoadHashTable
    For i = 1 To 1000000
        dummy = HashLookups(sample)
    Next i
    Debug.Print "HashLookups: ", Timer - starting

그것은 너무 초라하지 않은 것으로 드러났습니다.

HashLookups:                               1.655273

최종 버전

일어나서 해시 룩업 대신 벡터 룩업을 시도해 보겠다고 생각했습니다(바이트 단위의 값 배열만 채우고 테스트에 사용).이는 256개의 요소 배열에 불과하다는 점에서 합리적인 것으로 보입니다. 기본적으로 진실 테이블입니다.

Private lookup(255) As Boolean 'Module level

Function VectorLookup(source As Variant) As String
    Dim chars() As Byte
    Dim outVal() As Byte

    chars = CStr(source)
    Dim bound As Long
    bound = UBound(chars)
    ReDim outVal(bound)

    Dim i As Long, pos As Long
    For i = 0 To bound Step 2
        Dim temp As Byte
        temp = chars(i)
        If lookup(temp) Then
            outVal(pos) = temp
            pos = pos + 2
        End If
    Next
    ReDim Preserve outVal(pos)
    VectorLookup = outVal
End Function

Private Sub GenerateTable()
    Dim i As Long
    For i = 48 To 57
        lookup(i) = True
    Next
    For i = 65 To 90
        lookup(i) = True
    Next
    For i = 97 To 122
        lookup(i) = True
    Next
End Sub

룩업 테이블이 한 번만 생성된다고 가정하면 위의 다른 순수한 VBA 방법보다 약 10-15% 더 빠르게 기록됩니다.

to ThunderFrame (LHS ThunderFrame의 입니다.)Mid$부터 더 을 얻었습니다.RegExp추가적인 작은 조정:

  • 사용하다Value2Value
  • 정수가 아닌루프 선언
  • .ignorecase = True입니다.

코드

    Sub Replace2()

    Dim inputSh As Worksheet
    Dim inputRng As Range
    Set inputSh = Sheets("Data")
    Set inputRng = inputSh.Range("A1:A30000")

    Dim outputSh As Worksheet
    Dim outputRng As Range
    Set outputSh = Sheets("Replace")
    Set outputRng = outputSh.Range("A1:A30000")

    Dim time1 As Double, time2 As Double
    time1 = MicroTimer

    Dim arr As Variant
    Dim objRegex As VBScript_RegExp_55.RegExp
    Dim i As Long

    Set objRegex = CreateObject("vbscript.regexp")
    With objRegex
            .Global = True
            .Pattern = "[^\w]"
    End With

    arr = inputRng.Value2
    For i = LBound(arr) To UBound(arr)
            arr(i, 1) = objRegex.Replace(arr(i, 1), vbNullString)
    Next i
    outputRng.Value2 = arr

    time2 = MicroTimer
    Debug.Print (time2 - time1) * 1000
    End Sub

처음이자 현재 가장 성능이 좋은 루틴의 기능을 다음과 같이 변경하면 데이터에 따라 성능이 최소 40-50% 향상됩니다.

Function AlphaNumericOnly(strSource As Variant) As String
    Dim i As Long
    Dim charCount As Long
    Dim strResult As String
    Dim char As String
    strResult = Space$(Len(strSource))
    For i = 1 To Len(strSource)
        char = Mid$(strSource, i, 1)
        Select Case Asc(char)
            Case 48 To 57, 65 To 90, 97 To 122: 'include 32 if you want to include space
                charCount = charCount + 1
                Mid$(strResult, charCount, 1) = char
        End Select
    Next
    AlphaNumericOnly = Left$(strResult, charCount)
End Function

저는 몇 가지 최적화를 사용했지만, 주로, 당신은 다시 할당했습니다.strResult루프에서 여러 번 반복됩니다. 이는 매우 비용이 많이 들고 문자열이 길면(루프가 더 많이 실행됨) 훨씬 더 비용이 많이 듭니다.훨씬 더 사용하기 좋습니다.Mid$.

그리고 $subfixed 함수를 사용하면 문자열에 최적화되므로 거기서도 더 나은 성능을 얻을 수 있습니다.

ReGEx 버전 최적화

방식은 은 late-bound Regex 접근성인능리제적을공지있다시사습니용고간하을연만을 사용하고 있습니다.CreateObject이는 초기에 바인딩된 강력한 유형의 참조로서 훨씬 더 빠를 것입니다.

또한 Regex 패턴과 옵션이 매번 동일하므로 regex 개체를 변수로 선언하고 아직 존재하지 않는 경우에만 생성한 다음 기존 regex를 매번 다시 사용할 수 있습니다.

Regex가 승자가 되어야 한다는 것은 사실이 아닙니다.아래의 두 번째 솔루션은 초기에 출시된 Regex보다 빠릅니다.첫 번째 솔루션은 Regex만큼 빠릅니다. 둘 다 네이티브 VBA 전용입니다.

흥미로운 질문입니다.Original InStr 방법은 OP의 질문에 표시된 결과보다 훨씬 빨라야 합니다.

VBA가 잘하지 못하는 문자열 연결로 인해 성능이 저하됩니다.끈이 길수록 더 나빠집니다.

아래의 제 InStr 메소드 버전은 연결을 전혀 사용하지 않습니다.그것은 원래 것보다 몇 배 더 빠릅니다.실제로 실행 속도는 늦은 리젝스와 일치합니다.이 InStr 버전은 VBA에 완전히 기본으로 제공되며 매우 빠릅니다.소스 문자열이 길수록 연결에 비해 속도가 빨라집니다.

또한 이 방법은 변형 버전 대신 문자열 함수의 ($) 버전을 활용하여 몇 가지 성능을 향상시킵니다.InStrB 약빠름보다 약간 .InStr 임시 변수를 입니다.t그리고.arx시간도 많이 절약할 수 있습니다.

Sub InStr_ExcelHero()

    Dim inputSh As Worksheet
    Dim inputRng As Range
        Set inputSh = Sheets("Data")
        Set inputRng = inputSh.Range("A1:A30000")

    Dim outputSh As Worksheet
    Dim outputRng As Range
        Set outputSh = Sheets("InStr")
        Set outputRng = outputSh.Range("A1:A30000")

    Dim time1 As Double, time2 As Double
        time1 = MicroTimer

    Dim i&, j&, p&, max&, arx$, t$, res$, arr
        arr = inputRng
        max = Len(arr(1, 1))

    Dim validVals$: validVals = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

        For i = LBound(arr) To UBound(arr)
            p = 0
            arx = arr(i, 1)
            res = Space$(max)
            For j = 1 To max
                t = Mid$(arx, j, 1)
                If InStrB(validVals, t) Then
                    p = p + 1
                    Mid$(res, p, 1) = t
                End If
            Next
            arr(i, 1) = Left$(res, p)
        Next

    outputRng = arr

    time2 = MicroTimer
    Debug.Print (time2 - time1) * 1000

End Sub

또한 아래 ArrayLookup 버전은 InStr_ExcelHero()보다 두 배 이상 빠릅니다.

사실, 아래의 방법은 초기에 묶인 Regex보다 더 빠릅니다!

이것은 네이티브 VBA입니다.종속성 없음.정규식보다 빠릅니다.다음 방법은 배열의 모든 요소를 영숫자로 전환하는 가장 빠른 방법입니다.사용자 지정 c++ dll 이외의 VBA에서 지정된 경우:

Sub ArrayLookup_ExcelHero()

    Const VALS$ = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

    Dim inputSh As Worksheet
    Dim inputRng As Range
        Set inputSh = Sheets("Data")
        Set inputRng = inputSh.Range("A1:A30000")

    Dim outputSh As Worksheet
    Dim outputRng As Range
        Set outputSh = Sheets("InStr")
        Set outputRng = outputSh.Range("A1:A30000")

    Dim time1 As Double, time2 As Double
        time1 = MicroTimer

    Dim i&, j&, p&, max&, t&, arx() As Byte, res() As Byte, arr
        arr = inputRng
        max = Len(arr(1, 1))

    Dim Keep&(0 To 255)
        For i = 1 To Len(VALS)
            Keep(Asc(Mid$(VALS, i, 1))) = 1
        Next

        For i = LBound(arr) To UBound(arr)
            p = 0
            ReDim res(0 To max)
            arx = StrConv(arr(i, 1), vbFromUnicode)
            For j = 0 To max - 1
                t = arx(j)
                If Keep(t) Then
                    res(p) = t
                    p = p + 1
                End If
            Next
            arr(i, 1) = StrConv(res, vbUnicode)
        Next

    outputRng = arr

    time2 = MicroTimer
    Debug.Print (time2 - time1) * 1000

End Sub

제가 이것을 밖에 버리겠습니다. 다른 것이 없다면, 그것이 어떻게 작동하는지 볼 것입니다.저는 그것도 조금 정리될 수 있을 거라고 확신합니다.

저의 희망은 문자가 글자인지 테스트하는 방법이 더 빨리 나오는 것입니다.번호 테스트가 조금 더 빨리 완료될 수 있다고 확신합니다.

Function AlphaNumeric(s As String) As String
    Dim char As String, tempStr As String
    Dim i As Integer
    Dim t As Variant

    For i = 1 To Len(s)
        char = Mid(s, i, 1)
        If IsLetter(char) Or IsNumber(char) Then
            tempStr = tempStr & char
        End If
    Next i
    AlphaNumeric = tempStr
End Function

Private Function IsLetter(s As String) As Boolean
    If UCase(s) = s And LCase(s) = s Then
        IsLetter = False
    Else:
        IsLetter = True
    End If
End Function

Private Function IsNumber(s As String)
    On Error GoTo 1
    s = s * 1
    IsNumber = True
    Exit Function
1:
    IsNumber = False
End Function

언급URL : https://stackoverflow.com/questions/40929620/what-is-the-fastest-way-to-turn-every-member-of-an-array-alphanumeric

반응형