Lo que he aprendido: expresiones regulares en Emacs

Hablé hace tiempo de las expresiones regulares por aquí (de hecho fue lo que inauguró la sección Lo que he aprendido) pero todavía no me había puesto a usarlas en serio en Emacs para buscar y reemplazar cosas. Algún día tiene que ser el día, así que voy a ver si puedo resumir aquí para futura referencia la sintaxis de las expresiones regulares de Emacs, cómo se usan para buscar y qué ventajas nos ofrecen a la hora de reemplazar texto.

Sintaxis

La sintaxis de las expresiones regulares de Emacs tiene muchas cosas en común con las de otros programas y lenguajes de programación pero también tiene sus peculiaridades. Con C-h S regexp podemos ver toda la información sobre las regexp de Emacs, como soy muy maja os resumo aquí algunas cosas:

  • Los símbolos ., +, *, ? y [] funcionan de la manera típica:
    • . sustituye a cualquier carácter excepto al de nueva línea. Por ejemplo, a.b pillará cualquier secuencia de tres caracteres que empiece por a y acabe con b.
    • * localiza el carácter precedente cualquier número de veces, incluido cero. Por ejemplo, ca* captará caaaa pero también c.
    • + lo mismo que el anterior pero obligando a que el carácter precedente aparezca como mínimo una vez. Al contrario que ca*, ca+ no captará c. Para no confundirlo con el anterior a este le llamo el uno o más.
    • ? similar a * pero solo capta el carácter precedente una vez o cero. Siguiendo con el ejemplo, ca? captará c y ca? pero no caaa. Yo a este le llamo el si hay sí.
    • [] indica opciones. Por ejemplo, [ac]a encontrará las cadenas aa y ca. Su contrario es [^] que elimina las opciones entre corchetes, de este modo, [^ac]a encontrará ba pero no ca.
  • En Emacs hay clases sintácticas que empiezan por \s y su negación por \S. Por ejemplo, \sw indica un carácter de palabra (letras en minúscula o mayúscula y dígitos) y \s. un carácter de puntuación. A diferencia de otros programas, Emacs no interpreta \s como un espacio, para eso está \s-.

  • También tenemos clases sintácticas que se usan entre corchetes (adicionales a los que ya llevan) como [:digit:] para los números y [:alnum:] para los caracteres alfanuméricos. Una cosa a tener en cuenta es que estas clases varían según el modo.

  • Hay marcadores de borde, por ejemplo, \b indica el borde de palabra, y ^ y $ el inicio y el fin de línea respectivamente.

  • Podemos capturar grupos con \(CAPTURA\) para después hacer referencia a ellos con \N, donde N es un número que indica su posición. Por ejemplo, si hacemos \([[:digit:]]+\) capturaremos en la variable \1 una tira de números seguidos.

Para jugar con estas historias tenemos el modo interactivo re-builder en el que podemos escribir y modificar expresiones regulares y ver qué texto capturan. Para llamarlo hacemos:

M-x re-builder

¡Al loro! Este modo por defecto nos obliga a escapar doblemente las expresiones por lo que \b\sw+ se convierte en \\b\\sw+ y se convierte en una brasa brutal de escribir. Podemos cambiar este comportamiento en el archivo de configuración usando el estilo string en lugar que el read que usa por defecto:

(setq reb-re-syntax 'string)

Así las expresiones regulares de este modo serán como las que usamos en el resto de situaciones.

Buscar

Ahora que sabemos escribir expresiones regulares, veamos cómo nos ayudan en la vida. Lo más simple que podemos hacer es buscar cosas. Para ello tenemos por ejemplo el regexp I-search, que es como el I-search pero usando expresiones regulares. Es fácil recordar su combinación de teclas, es como la del I-search pero añadiendo M:

C-M-s

Al igual que el I-search normal, este nos marca en el texto todas los trocitos que cumplan nuestra regexp y volviendo a pulsar C-M-s vamos navegando entre ellas.

Reemplazar

Aquí es cuando las cosas se ponen interesantes. Gracias a esta herramienta podemos extraer información y reorganizarla como nos parezca. Simplemente usamos el modo Regexp Replace y la magia de las expresiones regulares:

M-x replace-regexp RET expresión regular RET sustitución

Os cuento un caso concreto. Estaba escribiendo un estado del arte en Markdown pero estaba teniendo problemas con los filtros de Pandoc así que como solución momentánea había optado por escribir las referencias bibliográficas con estilo LaTeX, pasar de Markdown a LaTeX y compilar a pdf después. Estas referencias consisten en el comando \cite{} al que se le da como argumento la clave de la publicación en la base de datos. Como sigo la convención autor-año para las claves, tienen esta pinta:

\cite{autor2017}

Una vez solucionado el problema con el filtro, decidí pasar las referencias a sintaxis de Markdown para que todo fuera coherente, en este caso debería ser [@autor2017]. Necesitaba por lo tanto capturar las claves de las publicaciones y sustituir el comando \cite{} por [@]. Hice lo siguiente:

M-x replace-regexp RET \\cite{\(\sw+\)} RET [@\1]

Donde el \1 se refiere al grupo capturado \sw+, que en este caso son las claves de las publicaciones, y se me modificaron todas las referencias como yo quería. ¡Fantástico! Problema resuelto con una única línea. ¡Cómo se gana en eficiencia con un editor decente! 😀

regexp hamlet t-shirt
Foto de Prehensile Eye Licencia CC-BY-NC-SA

Referencias

15.6 Syntax of Regular Expressions en el manual de Emacs

15.10.2 Regexp Replacement en el manual de Emacs

RegularExpression en Emacs Wiki

Emacs: how to replace a string using a regular expression? en StackOverflow

Emacs: Regex Tutorial en ErgoEmacs

Comparing regular expressions in Perl, Python, and Emacs

Anuncios

3 pensamientos en “Lo que he aprendido: expresiones regulares en Emacs

  1. Pingback: En que ando: octubre | Onda Hostil

¡Opina sin miedo! (Puedes usar Markdown)

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s