2011-07-07 30 views
11

He escrito 2 RE para hacer coincidir varias secuencias de cadenas en una cadena. por ej. supongamos que las dos expresiones regulares son RE1, RE2. Las cadenas pueden estar en estas 4 formas;Fusionar varias expresiones regulares en una RE

 
1) Match ONLY RE1 'one or more times' 
2) Match ONLY RE2 'one or more times' 
3) Match RE1 'one or more times' AND match RE2 'one or more times' 
4) Match NEITHER RE1 NOR RE2 

Actualmente estoy usando if para comprobar cada uno de ellos, pero sé que es muy caro como lo estoy haciendo el juego para una cadena en particular varias veces. Pensé en usar 'o' | pero el problema con eso es que regex dejará de coincidir una vez que encuentre la primera secuencia coincidente y no continúe buscando otras. Quiero encontrar secuencias coincidentes 'una o más veces'.

Actualización:

 
eg: RE1 = (\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?) 
    RE2 = (\babc\b) 
String: *some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f 

Matches: '100/64h', '120h/90', 'abc', '200/100', 'abc', '100h/100f' 

Cómo puedo combinar estos 2 ER para hacer mi programa eficiente. Estoy usando Python para codificar esto.

+3

Por favor, después de su código actual. –

+2

No tiene ninguna bandera global que pueda establecer mientras usa | entre ustedes expresiones regulares? – Stephan

+0

@Mahin, esto _será_ útil para usted, aunque en PHP: http://stackoverflow.com/questions/6565379/preg-replace-with-multiple-patterns-replacements-at-once – Qtax

Respuesta

5

Usted dice "Sé que es muy caro, ya que estoy haciendo la coincidencia de una cadena en particular varias veces". Eso me sugiere que está ejecutando cada RE varias veces. En ese caso, está cometiendo un error que puede resolverse sin escribir un RE más complejo.

re1_matches = re.findall(re1, text) 
re2_matches = re.findall(re2, text) 

Esto dará como resultado dos listas de coincidencias. A continuación, puede realizar operaciones booleanas en esas listas para generar los resultados que necesite; o puede concatenarlos si necesita todas las coincidencias en una lista. También puede usar re.match (coincidencia anclado al principio de la cadena) o re.search (coincidir en cualquier lugar de la cadena) para cada uno de estos si no necesita listas de resultados, pero solo necesita saber que hay una coincidencia.

En cualquier caso, la creación de un RE más complejo en este caso probablemente no sea necesario o deseable.

Pero no está inmediatamente claro para mí exactamente lo que quiere, así que podría estar equivocado al respecto.


Algunas sugerencias sobre cómo usar operadores booleanos para procesar listas. En primer lugar algún tipo de configuración:

>>> re1 = r'(\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?)' 
>>> re2 = r'(\babc\b)' 
>>> re.findall(re1, text) 
['100/64h', '120h/90', '200/100', '100h/100f'] 
>>> re.findall(re2, text) 
['abc', 'abc'] 
>>> re1_matches = re.findall(re1, text) 
>>> re2_matches = re.findall(re2, text) 
>>> rex_nomatch = re.findall('conglomeration_of_sandwiches', text) 

and devuelve el primer resultado falso o el resultado final si todos los resultados son verdaderos.

>>> not re1_matches and re2_matches 
False 

Así que si quieres la lista y no un valor lógico plana, usted tiene que probar el resultado que desea última:

>>> not rex_nomatch and re1_matches 
['100/64h', '120h/90', '200/100', '100h/100f'] 

mismo modo:

>>> not rex_nomatch and re2_matches 
['abc', 'abc'] 

Si lo que desea es sepa que ambos RE generaron coincidencias, pero no necesita más, puede hacer esto:

>>> re1_matches and re2_matches 
['abc', 'abc'] 

Por último, he aquí una forma compacta para conseguir la concatenación si ambos ER generan partidos

>>> re1_matches and re2_matches and re1_matches + re2_matches 
['100/64h', '120h/90', '200/100', '100h/100f', 'abc', 'abc'] 
0

Si RE1 y RE2 pueden coincidir con los mismos caracteres de la cadena, revíselos por separado (¿RE1 coincide con la cadena? ¿RE2 hace coincidir la cadena?).

1

Uso | en su expresión regular y re.findall() es probablemente el camino a seguir, aquí está un ejemplo:

>>> pattern = re.compile(r"(\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?|\babc\b)") 
>>> pattern.findall("*some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f") 
['100/64h', '120h/90', 'abc', '200/100', 'abc', '100h/100f'] 

Si es válido para que sus patrones se superpongan, esto no funcionará.

+0

Y luego use esta herramienta para optimizar ellos: http://www.rexegg.com/regex-optimizations.html –

2

Pensé en usar 'o' | pero el problema con esto es que regex dejará de coincidir una vez que encuentre la primera secuencia coincidente y no continúe buscando otras.

Eso es lo que re.findall es para.

>>> import re 
>>> RE = r'(?:\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?)|(?:\babc\b)' 
>>> string = '*some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f' 
>>> re.findall(RE, string) 
['100/64h', '120h/90', 'abc', '200/100', 'abc', '100h/100f'] 

Nota el uso de la no captura de paréntesis (las cosas (?:...)). Si la expresión regular usó el paréntesis de agrupación de captura como normal, re.findall devolvería [('100/64h', ''), ('120h/90', ''), ('', 'abc'), ('200/100', ''), ('', 'abc'), ('100h/100f', '')].

6

tiene que escapar de la \ en el segundo RE:

RE1 = '(\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?)' 
RE2 = '(\\babc\\b)' 
s = '*some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f' 


p = re.compile('('+RE2+'|'+RE1+')'); 
matches = p.findall(s) 

for match in matches: 
    print(match[0]) 
Cuestiones relacionadas