2010-04-13 35 views
6

Tengo mucha experiencia con Perl y Ruby, pero soy nuevo en Python, así que espero que alguien me muestre la forma Pythonic para realizar la siguiente tarea. Quiero comparar varias líneas con múltiples expresiones regulares y recuperar el grupo correspondiente. En Rubí, sería algo como esto:Python comparando cadena contra varias expresiones regulares

# Revised to show variance in regex and related action. 
data, foo, bar = [], nil, nil 
input_lines.each do |line| 
    if line =~ /Foo(\d+)/ 
    foo = $1.to_i 
    elsif line =~ /Bar=(.*)$/ 
    bar = $1 
    elsif bar 
    data.push(line.to_f) 
    end 
end 

Mis intentos en Python están resultando bastante feo porque el grupo correspondiente se devuelve desde una llamada para que coincida con/de búsqueda de una expresión regular y Python no tiene ninguna asignación en los condicionales o cambiar declaraciones ¿Cuál es la manera pitónica de hacer (o pensar) sobre este problema?

+1

Consulte http://stackoverflow.com/questions/2554185/match-groups-in-python. – PaulMcG

+0

Sí, esa pregunta es lo que estaba buscando, ¡gracias! – maerics

Respuesta

0

Paul McGuire's solution de utilizar una clase intermedia REMatcher que lleva a cabo el partido, almacena el grupo de partido, y devuelve un valor lógico para el éxito/fall resultado para producir el código más legible para este propósito.

1

Algo como esto, pero más bonita:

regexs = [re.compile('...'), ...] 

for regex in regexes: 
    m = regex.match(s) 
    if m: 
    print m.groups() 
    break 
else: 
    print 'No match' 
+1

Intenté algo similar, pero quiero tomar diferentes acciones basadas en las coincidencias de expresiones regulares, así que pasé de una lista a un diccionario mapeando las expresiones regulares a lambdas que se llamarán si se encuentra una coincidencia pero crea un código confuso ... – maerics

1

Hay varias maneras de "unir un nombre sobre la marcha" en Python, como mi viejo recipe para "asignar y prueba"; en este caso, probablemente me elegir otro tal manera (suponiendo Python 2.6, necesita algunos cambios leves, si está trabajando con una versión antigua de Python), algo así como:

import re 
pats_marks = (r'^A:(.*)$', 'FOO'), (r'^B:(.*)$', 'BAR') 
for line in lines: 
    mo, m = next(((mo, m) for p, m in pats_mark for mo in [re.match(p, line)] if mo), 
       (None, None)) 
    if mo: print '%s: %s' % (m, mo.group(1)) 
    else: print 'NO MATCH: %s' % line 

Muchos detalles de menor importancia se pueden ajustar, por supuesto, (por ejemplo, elegí (.*) en lugar de (.*?) como el grupo correspondiente - son equivalentes dado el siguiente $, así que elegí la forma más corta ;-) - podría precompilar los RE, factorizar las cosas de manera diferente que la tupla pats_mark (por ejemplo, con un dict indexado por patrones de RE), etc.

Pero las ideas sustanciales, creo, son hacer que el st ructure controlado por datos, y vincular el objeto de coincidencia a un nombre sobre la marcha con la subexpresión for mo in [re.match(p, line)], un "bucle" sobre una lista de un solo elemento (genexps vincula nombres solo por bucle, no por asignación; algunos consideran usar esta parte de especificaciones de genexps para ser "complicado", pero considero que es una expresión perfectamente aceptable de Python, esp. ya que era considerado en el momento en que se estaban diseñando listcomps, los "ancestros" de genexps en cierto sentido).

-1

su regex simplemente toma lo que está después del tercer carácter en adelante.

for line in open("file"): 
    if line.startswith("A:"): 
     print "FOO #{"+line[2:]+"}" 
    elif line.startswith("B:"): 
     print "BAR #{"+line[2:]+"}" 
    else: 
     print "No match" 
+0

buena manera, pero usaría división y comparación: begin, rest = line.split (':', 1) if begin == "A": etc ... – moshez

+0

Esto es bueno pero estoy buscando algo más general, la expresión regular simple es sólo para fines explicativos, las expresiones regulares reales serían bastante complejas. – maerics

Cuestiones relacionadas