2011-02-07 7 views
6

Ejemplo de expresiones regularesexpresión regular en base a palabras clave de concordancia en Python

regex = re.compile('^page/(?P<slug>[-\w]+)/(?P<page_id>[0-9]+)/$') 
matches = regex.match('page/slug-name/5/') 
>> matches.groupdict() 
{'slug': 'slug-name', 'page_id': '5'} 

¿Hay una manera fácil de pasar un diccionario de nuevo a la expresión regular para reconstruir una cadena?

es decir {'slug': 'new-slug', 'page_id': '6'} produciría page/new-slug/6/

Respuesta

1

Aquí es una solución utilizando sre_parse

import re 
from sre_parse import parse 

pattern = r'^page/(?P<slug>[-\w]+)/(?P<page_id>[0-9]+)/$' 
regex = re.compile(pattern) 
matches = regex.match('page/slug-name/5/') 
params = matches.groupdict() 
print params 
>> {'page_id': '5', 'slug': 'slug-name'} 

lookup = dict((v,k) for k, v in regex.groupindex.iteritems()) 
frags = [chr(i[1]) if i[0] == 'literal' else str(params[lookup[i[1][0]]]) \ 
    for i in parse(pattern) if i[0] != 'at'] 
print ''.join(frags) 
>> page/slug-name/5/ 

Esto funciona por el acaparamiento de los códigos de operación primas a través de análisis(), el vertido de los códigos de operación de posición (tienen 'a' para un primer parámetro), en sustitución de los grupos nombrados, y concatenar los frags cuando está hecho.

5

métodos Regex operan en cadenas. Puesto que usted tiene un dict, creo que el método de cadena format es un mejor ajuste:

In [16]: d={'slug': 'new-slug', 'page_id': '6'} 

In [17]: 'page/{slug}/{page_id}'.format(**d) 
Out[17]: 'page/new-slug/6' 

Hay todo tipo de expresiones regulares más complicado para el que el siguiente no funcionará, pero si siempre utiliza no -nested llamado grupos (?P<name>...) partidos y restringir pat a no tener nada más complicado que \A, o ^, \Z o $ o \b en su patrón de expresión de lo contrario, entonces tal vez usted podría hacer esto:

import re 
import string 


pat=r'\Apage/(?P<slug>[-\w]+)/(?P<page_id>[0-9]+)/\Z' 
regex = re.compile(pat) 
matches = regex.match('page/slug-name/5/') 
print(matches.groupdict()) 
# {'page_id': '5', 'slug': 'slug-name'} 

# Convert '(?P<slug>...)' to '{slug}'  
reverse_pat=re.sub(r'\(\?P<(.*?)>.*?\)',r'{\1}',pat) 
# Strip off the beginning^and ending $ 
reverse_pat=re.sub(r'^(?:\\A|\^)(.*)(?:\\Z|\$)$',r'\1',reverse_pat) 
# drop any `\b`s. 
reverse_pat=re.sub(r'\\b',r'',reverse_pat) 
# there are many more such rules one could conceivably need... 
print(reverse_pat.format(**matches.groupdict())) 
# page/slug-name/5/ 
1

Django's django.core.urlresolvers.reverse_helper parece ser capaz de hacer esto (curiosamente, usa expresiones regulares para analizar expresiones regex).

Puede reutilizar reverse_helper y MatchChecker que proporciona.

3

Aquí es una solución que no requiere una nueva expresión regular:

import re 
import operator 

regex = re.compile('^page/(?P<slug>[-\w]+)/(?P<page_id>[0-9]+)/$') 
matches = regex.match('page/slug-name/5/') 
groupdict = {'slug': 'new-slug', 'page_id': '6'} 
prev_index = matches.start(0) 
new_string = "" 
for group, index in sorted(regex.groupindex.iteritems(), key=operator.itemgetter(1)): 
    new_string += matches.string[prev_index:matches.start(index)] + groupdict[group] 
    prev_index = matches.end(index) 

new_string += matches.string[prev_index:matches.end(0)] 
print new_string 
# 'page/new-slug/6/' 

Esto funciona mediante la sustitución de los grupos nombrados por el valor proporcionado en groupdict, el resto de la cadena se inserta utilizando rebanadas en la cadena de entrada (matches.string). new_string será la parte de la cadena original que coincidió con la expresión regular con los reemplazos relevantes. Para obtener new_string para incluir incluso las partes no coincidentes de la cadena, reemplace prev_index = matches.start(0) con prev_index = 0 y elimine matches.end(0) del segmento final después del ciclo for.

+0

Este es un método muy bueno, más robusto que jugar con expresiones regulares como lo hice yo. – unutbu

Cuestiones relacionadas