2011-07-26 65 views
9

Estoy usando el plugin gedit regex (expresión regular de estilo de Python). Me gustaría hacer alguna operación aritmética en una referencia inversa a un grupo.Operaciones aritméticas en regex

Por ejemplo:

PART 1 DATA MODELS Chapter 
2 Entity-Relationship Model 27 

me gustaría cambiarlo a ser

PART 1 DATA MODELS Chapter 25 
2 Entity-Relationship Model 27 

Mi expresión regular es ^(PART.*)\n(.*\s(\d+))\n, y me gustaría reemplazarlo con algo como \1 (\3-2)\n\2\n donde \3-2 está destinado a ser la referencia inversa \3 menos 2. Pero la sustitución de expresiones regulares no es correcta. Me pregunto cómo hacerlo? ¡Gracias!

+0

¿De dónde vino la magia codificada 2, también se suponía que debía coincidir con la expresión regular desde el inicio de la segunda línea? – smci

+0

Para el registro, me gustaría señalar que este tipo de característica sería un riesgo de seguridad potencial. Primero es matemática, luego alguien quiere funciones, luego trigonometría o lo que sea, y finalmente alguien descubre un exploit de desbordamiento de pila o algo así. Así que tenga cuidado con lo que deseas. –

+0

¿Riesgo de seguridad? ¿De alguien malicioso corriendo gedit? No lo creo. Si ya están ejecutando gedit, ya pueden hacer cualquier cosa que se pueda hacer sin sudo. – Phob

Respuesta

3

No soy consciente de que puede hacer cálculos aritméticos u otros en expresiones regulares. Si hay un motor de expresiones regulares que lo respalde, ¡sería realmente ingenioso! Pero entiendo que eso no sería práctico sin desacelerar enormemente el motor de expresiones regulares.

creo que la mejor opción sería utilizar el sub función de expresiones regulares/método:

re.sub(pattern, repl, string[, count, flags]) 

devolver la cadena de obtenido mediante la sustitución de los sucesos que no se solapan más a la izquierda de patrón en cadena por la sustitución repl. Si no se encuentra el patrón, la cadena se devuelve sin cambios. repl puede ser una cadena o una función; si es una cadena, cualquier fuga de barra invertida se procesa. Es decir, \ n se convierte en un carácter de nueva línea simple, \ r se convierte en un salto de línea , y así sucesivamente. Los escapes desconocidos como \ j se quedan solos. Las referencias hacia atrás, como \ 6, se reemplazan con la subcadena que coincide con grupo 6 en el patrón. Por ejemplo:

>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', 
...  r'static PyObject*\npy_\1(void)\n{', 
...  'def myfunc():') 
'static PyObject*\npy_myfunc(void)\n{' 

Si repl es una función, es llamada para cada ocurrencia no superposición de patrón. La función toma un único argumento de objeto coincidente y devuelve la cadena de reemplazo . Por ejemplo:

>>> def dashrepl(matchobj): 
...  if matchobj.group(0) == '-': return ' ' 
...  else: return '-' 
>>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') 
'pro--gram files' 
>>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE) 
'Baked Beans & Spam' 

El patrón puede ser una cadena o un objeto RE.

El recuento de argumentos opcional es el número máximo de ocurrencias de patrón a reemplazar; count debe ser un entero no negativo. Si se omite o cero, todas las ocurrencias serán reemplazadas. Las coincidencias vacías para el patrón se reemplazan solo cuando no están adyacentes a una coincidencia previa, por lo que sub ('x *', '-', 'abc') devuelve '-a-b-c-'.

Además de escapes de caracteres y referencias hacia atrás como se describe anteriormente, \ g utilizará la subcadena coincidente por el grupo nombrado nombre, como se define por la (? P ...) sintaxis. \ g usa el número de grupo correspondiente ; \ g < 2> es por lo tanto equivalente a \ 2, pero no es ambiguo en un reemplazo como \ g < 2> 0. \ 20 sería interpretado como una referencia al grupo 20, no una referencia al grupo 2 seguido del carácter literal '0'.La referencia posterior \ g < 0> sustituye en toda la subcadena emparejada por el RE.

Puede pasar la función repl como una función que calcula los valores para sustituirlos por la cadena original.

+0

Si la aritmética se realiza después de la coincidencia, como parte de la operación de reemplazo, podría ser factible. Pero sí, la aritmética durante una búsqueda se reducirá a menos que las expresiones regulares puedan compilarse en una máquina virtual o algo así ... ow. –

1

A menos que gedit sea un superconjunto de Python, no permitirá las operaciones dentro de un reemplazo-regex como lo que intenta hacer con (\3-2). En cualquier caso, \3 es una cadena y usted necesitaría convertir con int() primero. Así que tendría que dividirlo en re.search (...), calcule el pageno insertado, luego inserte.

El segundo problema es que no coincidía con la longitud de página de '2', la codificaba en = - ¿Quería que su expresión regular coincidiera desde el inicio de la segunda línea?

(También en cualquier caso su partido de varias líneas sólo coincidirá una línea que sigue la pieza, si eso es lo que pretende.)

Aquí se implementa en la llanura de expresiones regulares de Python:

for (chap,sect,page) in re.finditer(r'^(PART.*)\n(.*\s+(\d+))\n', input, re.M): 
    print chap, int(page)-2 
    print sect 

(I intentado envolver eso como una réplica fn paginate_chapter(matchobj), no se puede obtener re.sub para llamar de manera confiable todavía ...)

5

el siguiente código hace lo que quiere en la cadena que dio como ejemplo. Un punto es que es muy específico para el formato de esta cadena, no puede gestionar la variabilidad de las cadenas: ¿está realmente limitado a este formato de cadena solamente?

import re 

ss = '''PART 1 DATA MODELS Chapter 
2 Entity-Relationship Model 27 

The sun is shining 

PART 1 DATA MODELS Chapter 
13 Entity-Relationship Model 45 
''' 

regx = re.compile('^(PART.*)(\n(\d*).*\s(\d+)\n)',re.MULTILINE) 

def repl(mat): 
    return ''.join((mat.group(1),' ', 
        str(int(mat.group(4))-int(mat.group(3))), 
        mat.group(2))) 

for mat in regx.finditer(ss): 
    print mat.groups() 

print 

print regx.sub(repl,ss) 

resultado

('PART 1 DATA MODELS Chapter', '\n2 Entity-Relationship Model 27\n', '2', '27') 
('PART 1 DATA MODELS Chapter', '\n13 Entity-Relationship Model 45\n', '13', '45') 

PART 1 DATA MODELS Chapter 25 
2 Entity-Relationship Model 27 

The sun is shining 

PART 1 DATA MODELS Chapter 32 
13 Entity-Relationship Model 45 

Editado: me habían olvidado la bandera re.MULTILINE

7

se puede pasar a re.sub función lambda que tiene re.MatchObject objeto para cada coincidencia de patrones que no se solapan y devuelve cadena de reemplazo. Por ejemplo:

import re  
print re.sub("(\d+)\+(\d+)", 
      lambda m: str(int(m.group(1))+int(m.group(2))), 
      "If 2+2 is 4 then 1+2+3+4 is 10") 

impresiones

Si 4 es 4, entonces 3 + 7 es 10

Desde aquí se puede aplicar a su problema.

+0

Gran respuesta, creo que esta debería ser la aceptada –

+0

Esta respuesta es increíble. ¡Gracias! – Avision

Cuestiones relacionadas