Estoy tratando de buscar caracteres especiales en una cadena.

Si el carácter especial existe en la cadena, el código devolverá un falso a la celda adyacente.

Dim arr(5)

arr(1) = "19"
arr(2) = "26"
arr(3) = "29"
arr(4) = "32"
arr(5) = "50"

'control characters check
For n = 1 To 5
    For x = 1 To 41
        If InStr(1, Range("b" & arr(n)), Chr(x)) = 0 Then
            For y = 123 To 255
                If InStr(Range("b" & arr(n)).Value, Chr(y)) > 0 Then
                    Range("e" & arr(n)).Value = "FALSE"
                    Exit For
                Else
                    Range("e" & arr(n)).Value = "TRUE"
                End If
            Next y
        Else
            Range("e" & arr(n)).Value = "FALSE"
            Exit For
        End If
    Next x
Next n

Mi problema es que realizar un bucle varias veces tomó bastante tiempo, ¿hay una forma más rápida de recorrer todos los datos ahorrando más tiempo?

Un ejemplo de los datos de cadena en la celda es: TY56D-CAT131BP342AC46-eL-W-00

0
Hank 16 jun. 2017 a las 11:47

3 respuestas

La mejor respuesta

Prueba esto:

Sub Test()
Dim arr(5) As String
Dim iLen As Integer, strV As String
Dim Found As Boolean: Found = False
Dim Test As Variant

arr(1) = "19"
arr(2) = "26"
arr(3) = "29"
arr(4) = "32"
arr(5) = "50"

For x = 1 To 5
    iLen = Len(Range("B" & arr(x)).Value)
    strV = Range("B" & arr(x)).Value
    For i = 1 To iLen
        Select Case Asc(Mid$(strV, i, 1))
        Case 1 To 41, 123 To 255
            Found = True
            Exit For
        End Select
    Next i
    If Found = False Then
       Range("E" & arr(x)).Value = "TRUE"
    Else
        Found = False
        Range("E" & arr(x)).Value = "FALSE"
    End If
Next x
End Sub

El tiempo de cálculo es casi instantáneo. Lo que difiere de su método es que reviso todos los caracteres y luego verifico si está permitido o no. En este caso, Select Case puede hacer esto mucho más rápido que un bucle for por cada char no permitido.

2
UGP 16 jun. 2017 a las 10:15

Prueba esto:

Sub CheckCharacters()
    Dim cl(5) As Integer, n As Integer

    cls = Array(19, 26, 29, 32, 50)

    For n = 0 To 4
        If IsValidString(Range("B" & cls(n))) Then
            Range("B" & cls(n)).Offset(0, 3) = "TRUE"
        Else
            Range("B" & cls(n)).Offset(0, 3) = "FALSE"
        End if
    Next n
End Sub

Function IsValidString(str As String) As Boolean
    Dim objRegEx As Object

    Set objRegEx = CreateObject("vbscript.regexp")

    objRegEx.Pattern = "^[\x2a-\x7a]+"
    objRegEx.Global = True
    objRegEx.IgnoreCase = True

    IsValidString = objRegEx.test(str)
End Function

Lo importante es:

"^[\x2a-\x7a]+"

Este es un Regex que solo es VERDADERO si la cadena solo contiene caracteres entre los valores ASCII 42 y 122 (que es lo que desea).

0
Alex P 16 jun. 2017 a las 09:54

Parece que te estás ralentizando mucho al referirte a

Range("b" & arr(n)).Value

Potencialmente hasta más de 120 veces en el bucle (que está anidado en otros bucles)

Lo que debería mejorar inmediatamente la velocidad de su macro es transferir el valor de Rango a una variable antes de este ciclo, por ejemplo:

dim search_string as string
search_string = Range("b" & arr(n)).Value

For y = 123 To 255
     If InStr(search_string, Chr(y)) > 0 Then
     Range("e" & arr(n)).Value = "FALSE"

También ahorraría un poco de tiempo convirtiendo todo su rango de búsqueda en una matriz y trabajando en eso, pero eso requeriría más trabajo, mientras que este es un cambio rápido que puede hacer que debería mejorar drásticamente el rendimiento

1
danl 16 jun. 2017 a las 09:35