Convirtiendo TXT en HTML. Conociendo expresiones regulares.

El otro día llegaron a mis manos por medio de un amigo unos CDs de formularios. Los formularios vienen en formato Word y en texto plano, para que cada cual elija el formato que prefiera. Yo me quedaré con los de texto plano. Cada formulario (algunos cientos) es un archivo distinto cuyo nombre es un número de tres cifras seguido de la partícula eu (formulario en euskara) o es (formulario en castellano) y la extensión .TXT, así que para facilitar la búsqueda del formulario que necesitamos se incluye un índice que nos dice qué contiene cada archivo. La idea es que primero uses el índice para saber qué número corresponde al formulario que necesitas (por ejemplo, el formulario 115 en castellano), y una vez localizado el número recurras al archivo correspondiente (115es.txt). Y visto esto me he dicho a mí mismo, “no debe de costar mucho pasar este índice a HTML para que sea un poco más fácil usar los formularios”. Y me he puesto manos a la obra.

Una opción sencilla pero tediosa sería editar el texto a mano, convirtiendo cada línea de texto plano en un hipervínculo que enlazara al correspondiente archivo TXT, pero eso sería un desperdicio de tiempo impresionante. Mejor vamos a buscar una manera algo más automatizada de conseguir el mismo efecto, vamos a utilizar la opción de reemplazo de texto de Kwrite, que es el editor de texto que suelo usar. Y para ello me voy a adentrar un poquito más en el apasionante mundo de las expresiones regulares, ya que mi contacto con él hasta ahora ha sido bastante tímido.

Lo primero, planificar el modus operandi. En realidad no he planificado nada, he ido improvisando en todo momento mediante la técnica de ensayo y error (sobre todo error), pero como quiero que esta explicación sea medianamente útil y además me siento incapaz de recordar la mayor parte de los errores que he cometido en el proceso, lo voy a explicar a toro pasado como si desde un principio la cosa hubiera estado clara. Así que vamos a echar un vistazo a la estructura del índice, que afortunadamente no es nada del otro jueves:

1.- Epígrafe Gordo
1.1.- Epígrafe mediano
001. Primer formulario
002. Segundo formulario
003. Tercer formulario
1.2.- Otro epígrafe mediano
1.2.1.- Sección
004. Cuarto formulario
1.2.2.- Otra sección
1.2.2.1.- Sub-sección
005. Quinto formulario

Más o menos quiero que quede así:

  • 1.- Epígrafe Gordo
  • 1.1.- Epígrafe mediano
  • 1.2.- Otro epígrafe mediano
    • 1.2.1.- Sección
  • 1.2.2.- Otra sección
    • 1.2.2.1.- Sub-sección

    Primera decisión: los Epígrafes Gordos irán entre <h2> y </h2>, los epígrafes medianos irán entre <h3> y </h3>, las secciones entre <h4> y </h4>, las sub-secciones entre <h5> y </h5>, y en la ultimísima clasificación, es decir, en los formularios, usaremos <p> y </p>. Luego nos curraremos una hoja de estilo chachi-guay para que quede clara la jerarquía.

    Vamos a convertir en párrafos todas las líneas que contienen los números y nombres de los formularios, y vamos a hacerlo de manera automática usando el reemplazo de texto. Vamos a pedirle a Kwrite que identifique todas las líneas que empiecen por un número de tres cifras, y les añada las etiquetas de inicio y fin de párrafo. Vamos a ello: Editar –> Reemplazar, en Texto a encontrar marcamos la casilla expresión regular, y en reemplazar con marcamos la casilla usar contenedores. Y entramos de lleno en el uso de las expresiones regulares, en el que soy un completo novato, así que lo explicaré como mejor pueda sin comprometerme a ser exacto ni mucho menos exhaustivo. En la casilla texto a encontrar deberemos introducir el criterio que queremos que se use para seleccionar las líneas. El primero, todas empiezan por un número del 0 al 9. O sea, [0-9]. Después viene otro número más, y otro más. Es decir:

    [0-9][0-9][0-9]

    Pero ojo, he dicho que empiezan con esos números, que no es lo mismo que decir que contienen esos números. Para marcar el inicio de una línea se usa el símbolo ^, así que nuestro principio de línea queda así:

    ^[0-9][0-9][0-9]

    ¿Y qué viene después? La verdad es que nos es indiferente, porque con esto nos basta para identificar todas las líneas que queríamos, así que vamos a terminarla de la manera más sencilla: el punto. El punto es algo así como el comodín, si ponemos un punto estamos indicando que se acepte cualquier caracter, sea el que sea. Si además de un punto le añadimos un asterisco estaremos indicando que se deberán tener en cuenta tantos caracteres como haya que cumplan el anterior criterio, con lo cual de esta manera estamos abarcando toda la línea hasta el final. Y para marcar el final de línea usaremos el símbolo del dólar:

    ^[0-9][0-9][0-9].*$

    Esto será suficiente para identificar las líneas que queremos modificar, pero ¿qué escribiremos en su lugar? No olvidemos que estamos sustituyendo, no añadiendo ni modificando. Si queremos que en el texto que les sustituya aparezca el texto original vamos a tener que especificar contenedores, o sea, porciones de texto que vamos a reutilizar en el reemplazo. Los contenedores se determinan con paréntesis, y yo voy a determinar dos por un motivo que explicaré más adelante. Así que ésta es la combinación definitiva para la casilla texto a encontrar:

    ^([0-9][0-9][0-9])(.*)$

    Vamos ahora al texto de reemplazo. Queremos que el texto sea reemplazado por sí mismo, pero con las etiquetas de párrafo (<p> y </p>) al principio y al final. Lo primero, volver a escribir el texto que reemplazamos. Hemos definido dos contenedores cuyos identificadores serán una barra oblícua y el número de contenedor que le corresponde. Es decir, al contenedor ([0-9][0-9][0-9]) le corresponde \1, y al contenedor (.*) le corresponde \2. Para que se copie tal cual tendremos que escribir \1\2, y si queremos invertir el orden de los elementos escribiremos \2\1. Incluso podemos repetirlos, por ejemplo, de esta manera: \1\2\1. Esto escribirá el número de tres cifras, luego todo el texto que viene después de los números, y de nuevo las tres cifras. Incluso podemos intercalar texto entre ambos elementos. Pero no vamos a complicarnos tanto, nos limitaremos a poner las etiquetas de párrafo a ambos extremos del texto:

    <p> \1\2</p>

    Ahora, pulsa Reemplazar. Sí, así de simple es, hemos convertido nuestras líneas de insulso texto plano en párrafos de un proto-documento HTML. Pero ojo, la cosa no acaba aquí, porque vamos a hacer algo más: vamos a convertir cada línea en un enlace a su correspondiente documento. Y aquí es donde daremos utilidad al hecho de haber definido dos contenedores en vez de uno. No es casual que hayamos aislado del resto de la línea las tres primeras cifras, que coinciden con parte del nombre del archivo al que hacen referencia. Es decir, la línea con el texto 001.No-sé-qué hace referencia al archivo 001es.txt (en el índice en euskara haría referencia al archivo 001eu.txt). Así que volvemos a empezar, rellenamos la casilla texto a encontrar exactamente de la misma manera, y hacemos la siguiente modificación a la casilla texto de reemplazo:

    <p><a href=””>\1\2</a></p>

    ¡Acabamos de convertir nuestros párrafos en hipervínculos! Sí, pero, ¿hipervínculos a dónde? Si 001.No-sé-qué nos debería llevar hasta 001es.txt, y 001 lo expresamos mediante el contenedor \1, adivinar la ruta de nuestro enlace no resultará complicado al barrapuntero medio:

    <p><a href=”\1es.txt“>\1\2</a></p>

    Además le he añadido un target=”_blank” al enlace, y en vez de enlazarlo al TXT he puesto extensión HTML y luego he renombrado los archivos, pero bueno, para simplificar lo he omitido en la explicación. La cuestión es que con esto ya hemos convertido en párrafos con enlace las referencias a los formularios, tal y como queríamos. Pero ojo, no hemos terminado: nos quedan los epígrafes, secciones y subsecciones. Una vez asimilado lo anterior esto ya resultará sencillo, aunque hay un par de variaciones. Empecemos por Epígrafes Gordos, que habíamos dicho que los identificaríamos mediante <h2> y </h2>. La característica que identifica a los Epígrafes Gordos y los diferencia del resto de elementos es que empiezan por un número de una o dos cifras (hay hasta 12), después hay un punto, después un guión, y luego ya el texto. Empecemos por las cifras. Si usamos la expresión [0-9] estaremos restringiendo la expresión a números de una sola cifra excluyendo los de dos o más, y si usamos la expresión [0-9][0-9] estaremos restringiendo la expresión a números de dos cifras excluyendo los de una, tres y más de tres cifras. Si usamos la expresión [0-9]* estaremos seleccionando las cadenas que consten de cualquier número de cifras, incluso cero cifras, cosa que no queremos. Solución: [0-9][0-9]*, que selecciona todas las cadenas en las que haya al menos una cifra, y potestativamente una, dos, tres, o mil más. Ojo: esto incluiría en nuestro criterio de búsqueda las cadenas que tuvieran tres cifras, es decir, todas las líneas que hemos marcado como párrafos mediante la anterior sustitución. Para evitar eso especificaremos que queremos que las cifras estén al principio de la línea:

    ^[0-9][0-9]*

    Después de las cifras debe ir siempre un punto, pero el punto en las expresiones regulares es un comodín que puede representa cualquier caracter, así que para que deje de ser un comodín y se comporte como un punto normal y corriente lo precederemos de una barra oblícua. Algo parecido pasa con el guión, así que también lo precederemos con una barra:

    ^[0-9][0-9]*\.\-

    ¿Y qué viene después? Después viene todo el texto que no sigue ningún patrón identificable, ni falta que nos hace. Usaremos el punto y el asterisco, y a correr. Añadimos la marca de final de línea, envolvemos todo entre paréntesis para que forme un contenedor, y tenemos listo nuestro texto a encontrar.

    ^([0-9][0-9]*\.\-.*)$

    Y sin complicaciones, lo sustituimos por el mismo texto envuelto entre las etiquetas de apertura y cierre <h2> y </h2> de una manera sencillísima, dado que sólo tenemos un contenedor que abarca toda la línea:

    <h2>\1</h2>

    Ahora vamos a por los epígrafes medianos, que llegado este punto resultarán sencillísimos. Dado que empieza por un número de una o dos cifras, un punto, otro número de una o dos cifras, un punto y un guión, donde antes pusimos “cifra-cifra-punto-guión” ahora pondremos “cifra-cifra-punto-cifra-cifra-punto-guión”. O sea, [0-9][0-9]*\.[0-9][0-9]*\.\-

    ^([0-9][0-9]*\.[0-9][0-9]*\.\-.*)$

    Y el texto de reemplazo será prácticamente igual, dado que seguimos teniendo un solo contenedor. Lo único que cambian son las etiquetas de apertura y cierre:

    <h3>\1</h3>

    Para los epígrafes inferiores el procedimiento es similar, sólo hay que añadir al texto a encontrar otra sesión de [0-9][0-9]*\.. Y ahora pasamos a otro grupo de formularios… ups… aquí los epígrafes se numeran con números romanos… Bueno, no hay problema: como los han escrito con mayúsculas cambiaremos [0-9][0-9]* por [A-Z][A-Z]*, y el resto igual.

    En fin, iba a explicar un par de pijadillas más, como el modo en el que he montado un índice abreviado al principio del documento y metido anclas en los títulos de los epígrafes, el modo en que he renombrado todos los 100es.txt a prefijo100es.html y he convertido todas las líneas de los mismos en párrafos (<p></p>), pero veo que me estoy alargando demasiado, y esto va a resultar ser un tocho infumable. Así que esto se acaba aquí, si le es útil a alguien, genial, y si no, no haber entrado. A mí me será útil tener esto aquí para cuando no recuerde tal o cual cosa y quiera repasarlo, ya que Barrapunto está más ordenado que mis notas. Y si alguien quiere comentar o sugerir algo, bienvenido sea. Un saludo.

    PD: Me acabo de dar cuenta de que quizás alguien quiera mejorar y reproducir estas explicaciones, así que allá va: Copyright 2005 Daniel Martínez. Se otorga permiso para copiar, distribuir y/o modificar el texto bajo los términos de la Licencia de Documentación Libre GNU, Versión 1.2 o cualquier otra versión posterior publicada por la Free Software Foundation; sin Secciones Invariantes, sin Cubierta Frontal, y sin
    Cubierta Posterior. Se puede obtener una copia de la licencia de gnu.org, también traducida al castellano, y comentada en la Wikipedia.

    Publicado en Barrapunto