Secuencias de números de tamaño fijo

El siguiente problema y sus soluciones se describen en el libro de J.E.F. Friedl [5]. Supongamos que tenemos un texto conteniendo códigos que son números de tamaño fijo, digamos seis dígitos, todos pegados, sin separadores entre ellos, como sigue:

012345678901123334234567890123125934890123345126

El problema es encontrar los códigos que comienzan por 12. En negrita se han resaltado las soluciones. Son soluciones sólo aquellas que, comienzan por 12 en una posición múltiplo de seis. Una solución es:

@nums = grep {m/^12/} m/\d{6}/g;

que genera una lista con los números y luego selecciona los que comienzan por 12. Otra solución es:

@nums = grep { defined } m/(12\d{4})|\d{6}/g;

que aprovecha que la expresión regular devolverá una lista vacía cuando el número no empieza por 12. Obsérvese que se esta utilizando también que el operador | no es greedy.

¿Se puede resolver el problema usando sólamente una expresión regular? Obsérvese que esta solución ``casi funciona'':

@nums = m/(?:\d{6})*?(12\d{4})/g;

recoge la secuencia mas corta de grupos de seis dígitos que no casan, seguida de una secuencia que casa. El problema que tiene esta solución es al final, cuando se han casado todas las soluciones, entonces la búsqueda exhaustiva hará que nos muestre soluciones que no comienzan en posiciones múltiplo de seis. Encontrará así números como el último resaltado:

012345678901123334234567890123125934890123345126
Por eso, Friedl propone esta solución:

@nums = m/(?:\d{6})*?(12\d{4})(?:(?!12)\d{6})*/g;

Se asume que existe al menos un éxito en la entrada inicial. Que es un extraordinario ejemplo de como el uso de paréntesis de agrupamiento simplifica y mejora la legibilidad de la solución. Es fantástico también el uso del operador de predicción negativo.

Casiano Rodríguez León
Licencia de Creative Commons
Principios de Programación Imperativa, Funcional y Orientada a Objetos Una Introducción en Perl/Una Introducción a Perl
por Casiano Rodríguez León is licensed under a Creative Commons Reconocimiento 3.0 Unported License.

Permissions beyond the scope of this license may be available at http://campusvirtual.ull.es/ocw/course/view.php?id=43.
2012-06-19