2012-07-30 13 views
5

Busco para crear una expresión regular VBA que se encuentra la existencia de dos cadenas particulares dentro de un conjunto de paréntesis.VBA expresiones regulares - coincidir con una expresión que no comienza con una palabra en particular

Por ejemplo, en esta expresión:

(AAA, BBB, CCC, ddd, aaa xxx)

de alguna manera me informes que se encuentra tanto "AAA" Y "xxx AAA" en el expresión. Es decir, dado que hay una coincidencia en "aaa" sin el "xxxx" al frente, y también hay una coincidencia en "xxx aaa" más adelante en la expresión, debería ser verdadera. Dado que estas dos secuencias pueden aparecer en cualquier orden, lo contrario también debería ser cierto.

así que estoy pensando la expresión/s sería algo como esto:

"(xxx aaa" [^ x] [x ^] [^ x] [x ^] aaa) "

para encontrar las palabras en un orden y

"(aaa" [^ x] [x ^] [^ x] [x ^] xxx aaa)"

para las palabras en otro orden.

¿Tiene esto sentido? ¿O hay un mejor enfoque?

Sé que esto está cambiando la especificación, pero hay una adición importante - no puede haber ningún paréntesis, intercediendo entre los términos.

Así, por ejemplo, este DEBERÍAMOS partido:

(AAA, BBB, CCC, DDD, (eee, aaa xxx))

En otras palabras, estoy tratando de parecer en medio de un juego de paréntesis solo.

+0

Se puede eliminar los paréntesis y llame a [ 'Split'] (http://msdn.microsoft.com/en-us/library/6x627e5f (v = vs.80) .aspx) para separar las entradas en una matriz que puede buscar? – mellamokb

+0

¿no podría usar la función InStr para esto? ¿Podría simplemente usar una variable booleana o algo así y establecerlo en verdadero si encuentra una ubicación para la frase que está buscando en la cadena? Función InStr encontrada aquí: http://msdn.microsoft.com/en-us/library/8460tsh1(v=vs.80).aspx –

+0

Intenté responder a su pregunta lo mejor posible, pero no está claro en su definición del problema. ** a) ** Regex nunca tendrá la noción de * "paréntesis coincidentes" *. Es técnicamente imposible. ** b) ** Pareces asumir que ',' es algún tipo de separador, pero nunca realmente defines eso. – Tomalak

Respuesta

1

de ancho cero son de su amigo.

Function FindInParen(str As String, term1 As String, term2 As String) As Boolean 
    Dim re As New VBScript_RegExp_55.RegExp 

    re.Pattern = "\(" & _ 
       "(?=[^()]*)\)" & _ 
       "(?=[^()]*\b" & RegexEscape(term1) & "\b)" & _ 
       "(?=[^()]*\b" & RegexEscape(term2) & "\b)" 

    FindInParen = re.Test(str) 
End Function 

Function RegexEscape(str As String) As String 
    With New VBScript_RegExp_55.RegExp 
    .Pattern = "[.+*?^$|\[\](){}\\]" 
    .Global = True 
    RegexEscape = .Replace(str, "\$&") 
    End With 
End Function 

Este patrón se lee como:

  • a partir de una paren de apertura, visita:
    • que un paren de cierre coincidente sigue en algún lugar y no hay parens anidado dentro
    • que term1 se produce antes de la Paréntesis de cierre
    • que term2 ocurre antes de los paréntesis de cierre

Desde que estoy usando preanálisis ((?=...)), el motor de expresiones regulares en realidad nunca se mueve hacia adelante en la cadena, por lo que puede encadenar tantas afirmaciones de preanálisis y hacer que todos se comprueban.Un efecto secundario es que el orden en el que term1 y term2 aparecen en la cadena no es relevante.

he comprobado en la consola ("ventana Inmediato"):

? FindInParen("(aaa, bbb, ccc, ddd, xxx aaa)", "aaa", "xxx aaa") 
True 

? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "aaa", "xxx aaa") 
True 

? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "bbb", "xxx aaa") 
False 

Notas:

  • rendimientos La segunda prueba True porque-técnicamente tanto aaa y xxx aaa están dentro del mismo conjunto de parens.
  • Regex no puede tratar con estructuras anidadas. Nunca se obtendrán paréntesis anidados a la derecha con expresiones regulares. Nunca podrá encontrar "un conjunto coincidente de parens" con expresiones regulares solamente, solo un par de apertura/cierre que no tiene otros pares intermedios. Escribe un analizador si necesitas manejar el anidamiento.
  • Haga una referencia a "Microsoft VBScript Regular Expressions 5.5" en su proyecto.

Fwiw, he aquí una función de anidación-conscientes mínima que trabaja para el segundo caso de prueba anterior:

Function FindInParen(str As String, term1 As String, term2 As String) As Boolean 
    Dim parenPair As New VBScript_RegExp_55.RegExp 
    Dim terms As New VBScript_RegExp_55.RegExp 
    Dim matches As VBScript_RegExp_55.MatchCollection 

    FindInParen = False 
    parenPair.Pattern = "\([^()]*\)" 
    terms.Pattern = "(?=.*?[(,]\s*(?=\b" & RegexEscape(Trim(term1)) & "\b))" & _ 
        "(?=.*?[(,]\s*(?=\b" & RegexEscape(Trim(term2)) & "\b))" 

    Do 
    Set matches = parenPair.Execute(str) 
    If matches.Count Then 
     If terms.Test(matches(0).Value) Then 
     Debug.Print "found here: " & matches(0).Value 
     FindInParen = True 
     End If 
     str = parenPair.Replace(str, "[...]") 
    End If 
    Loop Until FindInParen Or matches.Count = 0 

    If Not FindInParen Then 
    Debug.Print "not found" 
    End If 

    If InStr("(", str) > 0 Or InStr(")", str) > 0 Then 
    Debug.Print "mis-matched parens" 
    End If 
End Function 

Consola:

? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "aaa", "xxx aaa") 
not found 
False 

? FindInParen("(aaa, bbb, ccc, ddd, (eee, xxx aaa))", "eee", "xxx aaa") 
found here: (eee, xxx aaa) 
True 
+0

Agregaría global (vea la respuesta de tim williams a continuación) y recorra todos los términos coincidentes. Muy útil, gracias. –

+0

@JackBeNimble Agregar "global" a los 'terms.Pattern' no tendría sentido, ya que siempre devuelve la cadena vacía. – Tomalak

+0

Ok, pero el segundo caso de prueba anterior devuelve falso para mí, en ambas iteraciones de la función. No estoy seguro de por qué, es difícil descubrir las expresiones. –

1

En realidad no es claro por su pregunta exactamente lo que quiere (y tal vez Regexp no es realmente necesario aquí) pero esto podría estar cerca:

asserttions Look-Ahead
Sub Tester() 
    RegexpTest ("(aaa, bbb, ccc, ddd, xxx aaa)") 
End Sub 


Sub RegexpTest(txt As String) 
    Dim re As Object 
    Dim allMatches, m 

    Set re = CreateObject("VBScript.RegExp") 
    re.Pattern = "([^,\(]*aaa)" 
    re.ignorecase = True 
    re.Global = True 

    Set allMatches = re.Execute(txt) 

    For Each m In allMatches 
     Debug.Print Trim(m) 
    Next m 

End Sub 
Cuestiones relacionadas