En la sección anterior, tratamos con
un patrón donde el mismo carácter podía repetirse hasta tres veces. Hay
otra manera de expresar esto con expresiones regulares, que algunas
personas encuentran más legible. Primero mire el método que hemos usado ya
en los ejemplos anteriores.
Ejemplo 7.5. La manera antigua: cada carácter es opcional
>>> import re
>>> pattern = '^M?M?M?$'
>>> re.search(pattern, 'M')
<_sre.SRE_Match object at 0x008EE090>
>>> pattern = '^M?M?M?$'
>>> re.search(pattern, 'MM')
<_sre.SRE_Match object at 0x008EEB48>
>>> pattern = '^M?M?M?$'
>>> re.search(pattern, 'MMM')
<_sre.SRE_Match object at 0x008EE090>
>>> re.search(pattern, 'MMMM')
>>>
|
Esto coincide con el inicio de la cadena, luego la primera
M opcional, pero no la segunda y la tercera (pero no
pasa nada, porque son opcionales), y luego el fin de la cadena.
|
|
Esto coincide con el inicio de la cadena, luego la primera y segunda
M opcionales, pero no la tercera M
(pero no pasa nada, porque es opcional), y luego el fin de la
cadena.
|
|
Esto coincide con el principio de la cadena, y luego con las tres
M opcionales, antes del fin de la cadena.
|
|
Esto coincide con el principio de la cadena, y luego las tres
M opcionales, pero no encontramos el fin de la cadena
(porque aún hay una M sin emparejar), así que el patrón
no coincide y devuelve None.
|
Ejemplo 7.6. La nueva manera: de n a
m
>>> pattern = '^M{0,3}$'
>>> re.search(pattern, 'M')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MM')
<_sre.SRE_Match object at 0x008EE090>
>>> re.search(pattern, 'MMM')
<_sre.SRE_Match object at 0x008EEDA8>
>>> re.search(pattern, 'MMMM')
>>>
|
Este patrón dice: “Coincide con el principio de la cadena,
luego cualquier cosa entre cero y tres caracteres M, y
luego el final de la cadena”. 0 y 3 podrían ser números cualquiera;
si queremos que haya al menos una M pero no más de
tres, podríamos escribir M{1,3}.
|
|
Esto coincide con el principio de la cadena, luego una de tres
posibles M, y luego el final de la cadena.
|
|
Esto coincide con el principio de la cadena, luego dos de tres
posibles M, y luego el final de la cadena.
|
|
Esto coincide con el principio de la cadena, luego tres de tres
posibles M, y luego el final de la cadena.
|
|
Esto coincide con el principio de la cadena, luego tres de tres
posibles M, pero entonces no
encuentra el final de la cadena. La expresión regular nos
permitía sólo hasta tres caracteres M antes de
encontrar el fin de la cadena, pero tenemos cuatro, así que el patrón no
coincide y se devuelve None.
|
7.4.1. Comprobación de las decenas y unidades
Ahora expandiremos la expresión regular de números romanos para
cubrir las decenas y unidades. Este ejemplo muestra la comprobación de las
decenas.
Ejemplo 7.7. Comprobación de las decenas
>>> pattern = '^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)$'
>>> re.search(pattern, 'MCMXL')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCML')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLX')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLXXX')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLXXXX')
>>>
|
Esto coincide con el principio de la cadena, luego la primera
M opcional, después con CM, y
XL, para coincidir por último con el fin de la cadena.
Recuerde, la sintaxis (A|B|C) significa “coincide
exactamente con un patrón de entre A, B o C”. Encontramos
XL, así que se ignoran las posibilidades
XC y L?X?X?X?, y después pasamos al
final de la cadena. MCML es el número romano que
representa 1940.
|
|
Esto coincide con el principio de la cadena, y la primera
M opcional, después CM, y
L?X?X?X?. De L?X?X?X?, coincide con
la L y descarta los tres caracteres opcionales
X. Ahora pasamos al final de la cadena.
MCML es la representación en romanos de
1950.
|
|
Esto coincide con el principio de la cadena, luego con la primera
M opcional, y con CM, después con la
L opcional y con la primera X
opcional, ignora las otras dos X opcionales y luego
encuentra el final de la cadena. MCMLX representa en
números romanos 1960.
|
|
Esto encuentra el principio de la cadena, luego la primera
M opcional, después CM, luego la
L opcional y las tres X opcionales,
y por último el fin de la cadena. MCMLXXX es el número
romano que representa 1980.
|
|
Esto coincide con el principio de la cadena, y la primera
M opcional, luego CM, y después la
L y las tres X opcionales, para
entonces fallar al intentar coincidir con el fin de
la cadena, debido a que aún resta una X sin justificar.
Así que el patrón al completo falla, y se devuelve None.
MCMLXXXX no es un número romano válido.
|
La expresión de las unidades sigue el mismo patrón. Le ahorraré los
detalles mostrándole el resultado final.
¿Cómo se vería esto usando su sintaxis alternativa
{n,m}? El ejemplo nos muestra la nueva sintaxis.
Ejemplo 7.8. Validación de números romanos con {n,m}
>>> pattern = '^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
>>> re.search(pattern, 'MDLV')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MMDCLXVI')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MMMMDCCCLXXXVIII')
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'I')
<_sre.SRE_Match object at 0x008EEB48>
|
Esto coincide con el principio de la cadena, después con uno de las
cuatro M posibles, luego con
D?C{0,3}. De estos, coincide con la
D opcional y ninguna de las tres posibles
C. Seguimos, y coincide con L?X{0,3}
con la L opcional y ninguna de las tres posibles
X. Entonces coincide con V?I{0,3} al
encontrar la V opcional y ninguna de las tres posibles
I, y por último el fin de la cadena.
MDLV es la representación en romanos de
1555.
|
|
Esto coincide con el principio de la cadena, luego dos de las cuatro
posibles M, entonces con D?C{0,3}
por una D y una C de tres posibles;
luego con L?X{0,3} por la L y una de
tres X posibles; después con
V?I{0,3} por una V y una de tres
posibles I; y por último, con el fin de la cadena.
MMDCLXVI es la representación en números romanos de
2666.
|
|
Esto coincide con el principio de la cadena, luego con cuatro de
cuatro M posibles, después con
D?C{0,3} por una D y tres de tres
posibles C; entonces con L?X{0,3}
por la L y las tres X de tres; luego
con V?I{0,3} por la V y tres de tres
I; y por último con el final de la cadena.
MMMMDCCCLXXXVIII es la representación en números
romanos de 3888, y es el número romano más largo que
se puede escribir sin usar una sintaxis extendida.
|
|
Observe atentamente (me siento como un mago. “Observen
atentamente, niños, voy a sacar un conejo de mi sombrero.”). Esto
coincide con el principio de la cadena, y con ninguna de las cuatro
posibles M, luego con D?C{0,3} al
ignorar la D y coincidiendo con cero de tres
C, después con L?X{0,3} saltándose
la L opcional y con cero de tres X,
seguidamente con V?I{0,3} ignorando la
V opcional y una de tres posibles I.
Y por último, el fin de la cadena. ¡Guau!.
|
Si ha conseguido seguirlo todo y lo ha entendido a la primera, ya lo
hizo mejor que yo. Ahora imagínese tratando de entender las expresiones
regulares de otra persona, en mitad de una parte crítica de un programa
grande. O incluso imagínese encontrando de nuevo sus propias expresiones
regulares unos meses más tarde. Me ha sucedido, y no es una visión
placentera.
En la siguiente sección exploraremos una sintaxis alternativa que le
puede ayudar a hacer mantenibles sus expresiones.