2009-12-09 31 views
12

El uso de str.format() es el nuevo estándar para formatear cadenas en Python 2.6 y Python 3. Me he encontrado con un problema al usar str.format() con expresiones regulares.Python 2.6+ str.format() y expresiones regulares

He escrito una expresión regular para devolver todos los dominios que son un solo nivel por debajo de un dominio especificado, o cualquier dominios que son 2 niveles por debajo del dominio especificado, si el segundo nivel por debajo es www ...

Suponiendo que el dominio especificado es delivery.com, mi expresión regular debe devolver a.delivery.com, b.delivery.com, www.c.delivery.com ... pero no debe devolver xadelivery.com.

import re 

str1 = "www.pizza.delivery.com" 
str2 = "w.pizza.delivery.com" 
str3 = "pizza.delivery.com" 

if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}delivery.com$', str1): print 'String 1 matches!' 
if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}delivery.com$', str2): print 'String 2 matches!' 
if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}delivery.com$', str3): print 'String 3 matches!' 

La ejecución de este debe dar el resultado:

String 1 matches! 
String 3 matches! 

Ahora, el problema es cuando intento de sustituir delivery.com dinámicamente usando str.format ...

if (re.match('^(w{3}\.)?([0-9A-Za-z-]+\.){1}{domainName}$'.format(domainName = 'delivery.com'), str1): print 'String 1 matches!' 

Este parece fallar, porque el str.format() espera que {3} y {1} sean parámetros de la función. (Estoy suponiendo)

pude concatenar la cadena mediante operador +

'^(w{3}\.)?([0-9A-Za-z-]+\.){1}' + domainName + '$' 

La cuestión se reduce a, es posible utilizar str.format() cuando la cadena (por lo general de expresiones regulares) tiene "{n} "dentro de él?

+0

No está directamente relacionado con la pregunta, pero se ahorrará un montón de dolor más tarde al adquirir el hábito de usar siempre cadenas sin formato en su expresión regular. –

+0

@Mark ¿cuáles son las razones para esto? Gracias por el consejo. – brildum

+4

Como regla general, cada vez que ponga barras diagonales inversas en literales de cadenas, debe usar cadenas sin formato. De lo contrario, puede terminar con escapes inesperados de cadenas. Esto es más evidente en las rutas de archivos de Windows donde (no cruda) "c: \ names \ bob" no significa lo que usted piensa que significa. En una expresión regular, usar una cadena sin formato significa que tu cadena de expresiones regulares es lo que escribes. Para hacer coincidir una barra diagonal inversa en una expresión regular, debe escapar de ella con otra: \\ Sin embargo, esa secuencia en una cadena no cruda produce una sola barra diagonal inversa, pero no es obvio al observar su expresión regular. En una cadena sin formato, su r '\\' se produce como se esperaba. –

Respuesta

20

primero necesitaría formatear la cadena y luego usar regex. Realmente no vale la pena poner todo en una sola línea. Se puede hacer Escape con la duplicación de las llaves:

>>> pat= '^(w{{3}}\.)?([0-9A-Za-z-]+\.){{1}}{domainName}$'.format(domainName = 'delivery.com') 
>>> pat 
'^(w{3}\\.)?([0-9A-Za-z-]+\\.){1}delivery.com$' 
>>> re.match(pat, str1) 

Además, re.match se emparejan en el principio de la cadena, usted no tiene que poner ^ si utiliza re.match, necesita ^ si está usando re.search , sin embargo.

Tenga en cuenta que {1} en expresiones regulares es bastante redundante.

+4

No solo es '{1}' redundante, sino que 'www' no sería más claro que' w {{3}} '.Sé que no responde a la pregunta general original, pero parece una mejor solución para este caso. –

7

por the documentation, si necesita un literal o {} para sobrevivir a la opertation formato, utilice {{ y }} en la cadena original.

'^(w{{3}}\.)?([0-9A-Za-z-]+\.){{1}}{domainName}$'.format(domainName = 'delivery.com') 
Cuestiones relacionadas