2010-12-02 17 views
15

Tengo expresión regular dinámica en la que no sé de antemano el número de grupos que tiene me gustaría reemplazar todas las coincidencias con etiquetas XMLreemplazar todas las coincidencias de expresiones regulares en una sola línea

ejemplo

re.sub("(this).*(string)","this is my string",'<markup>\anygroup</markup>') 
>> "<markup>this</markup> is my <markup>string</markup>" 

¿eso es posible incluso en una sola línea?

Respuesta

23

Para una expresión regular constante como en su ejemplo, hacer

re.sub("(this)(.*)(string)", 
     r'<markup>\1</markup>\2<markup>\3</markup>', 
     text) 

en cuenta que necesita para encerrar. * Entre paréntesis, así si usted no quiere hacer perder.

Ahora, si no sabes cómo es la expresión regular, es más difícil, pero debería ser factible.

pattern = "(this)(.*)(string)" 
re.sub(pattern, 
     lambda m: ''.join('<markup>%s</markup>' % s if n % 2 == 0 
         else s for n, s in enumerate(m.groups())), 
     text) 

Si lo primero que acompañado de su patrón no necesariamente tiene que ser marcado, utilizar esto en su lugar, con el primer grupo que coincida con opcionalmente un texto de prefijo que se debe dejar solos:

pattern = "()(this)(.*)(string)" 
re.sub(pattern, 
     lambda m: ''.join('<markup>%s</markup>' % s if n % 2 == 1 
         else s for n, s in enumerate(m.groups())), 
     text) 

Ya entendiste la idea.

Si sus expresiones regulares son complicados y no está seguro de que puede hacer que todo parte de un grupo, en el que sólo cada segundo grupo tiene que ser marcado, es posible hacer algo más inteligente con una función más complicada:

pattern = "(this).*(string)" 
def replacement(m): 
    s = m.group() 
    n_groups = len(m.groups()) 
    # assume groups do not overlap and are listed left-to-right 
    for i in range(n_groups, 0, -1): 
     lo, hi = m.span(i) 
     s = s[:lo] + '<markup>' + s[lo:hi] + '</markup>' + s[hi:] 
    return s 
re.sub(pattern, replacement, text) 

Si necesita manejar grupos superpuestos, está solo, pero debería ser factible.

+0

¿Qué representa el m en lamba m? – bikashg

+0

La 'm' significa' match', el objeto de coincidencia [regexp] (https://docs.python.org/3/library/re.html#match-objects). –

5

re.sub() reemplazará todo lo que pueda. Si le pasa una función para repl, puede hacer aún más.

+0

estoy esperando mi partido que aparezca entre \ 1 | \ 2 | \ 3 .. damir

1

Sí, esto se puede hacer en una sola línea.

>>> re.sub(r"\b(this|string)\b", r"<markup>\1</markup>", "this is my string") 
'<markup>this</markup> is my <markup>string</markup>' 

\b asegura que sólo palabras completas se hacen coincidir.

Así que si usted tiene una lista de palabras que usted necesita para marcar, se puede hacer lo siguiente:

>>> mywords = ["this", "string", "words"] 
>>> myre = r"\b(" + "|".join(mywords) + r")\b" 
>>> re.sub(myre, r"<markup>\1</markup>", "this is my string with many words!") 
'<markup>this</markup> is my <markup>string</markup> with many <markup>words</markup>!' 
Cuestiones relacionadas