Reemplazo mediante expresiones regulares en Emacs

Reemplazo mediante expresiones regulares en Emacs
Índice

A raiz de leer este artículo de Angel he vuelto a intentar lo que hace un tiempo dejé por imposible. Se trata del reemplazo de cadenas de texto definidas mediante expresiones regulares y de forma recursiva en distintos archivos de varios directorios gracias a Emacs.

Recordemos el problema que me asaltó cuando tuve que cambiar el formato de todos los encabezados que hasta entonces tenía escritos en los artículos del blog, sólo hay que cambiar esto …

# Encabezado 1 #
Lo que sea
## Encabezado 2 ##
Lo que sea
### Encabezado 3 ###
Lo que sea

… por esto …

# Encabezado 1
Lo que sea
## Encabezado 2
Lo que sea
### Encabezado 3
Lo que sea

… en todos los archivos “*.md” dento de un directorio.

Antes de seguir adelante hay que tener en cuenta unas de las peculiaridades que tiene Emacs en lo que se refiere al manejo de expresiones regulares y que en este caso nos van a afectar.

  • Para definir un espacio en blanco → \s-
  • Para definir un grupo → \(...\)

Reemplazando en un archivo

Abriremos en un buffer el archivo en el que queremos realizar el reemplazo e introduciremos el comando

M-x replace-regexp
  • Cadena a buscar → \(#+\s-\)\(.+\)\(\s-#+\)
  • Cadena a reemplazar → \1\2

Reemplazar en varios archivos

Ahora vamos a usar Dired para seleccionar los archivos en los que queremos realizar la modificación. Abriremos Dired mediante el comando C-x d e indicando la ruta donde están los archivos a editar.

  /home/sherlockes/prueba:
  total used in directory 16K available 76305356
  -rw-rw-r-- 1 sherlockes 360 mar 11 10:53 archivo_1.md
  -rw-rw-r-- 1 sherlockes 444 mar 12 11:44 archivo_2.md
  -rw-rw-r-- 1 sherlockes 444 mar 12 11:44 archivo_3.md
  -rw-rw-r-- 1 sherlockes 444 mar 12 11:44 archivo_4.txt

Para selecionar de forma automática todos los archivos “*.md” del directorio usaremos el comando % m y posteriormente introduciremos .md$.

Tal y como se explica en el artículo de Angel es posible marcar los archivos con la letra m de uno en uno y desmarcar con la letra u. Para seleccionar todos los archivos de un directorio con el atajo C-u t.

  /home/sherlockes/Descargas/tmp:
  total used in directory 16K available 76305356
* -rw-rw-r-- 1 sherlockes 360 mar 11 10:53 archivo_1.md
* -rw-rw-r-- 1 sherlockes 444 mar 12 11:44 archivo_2.md
* -rw-rw-r-- 1 sherlockes 444 mar 12 11:44 archivo_3.md
  -rw-rw-r-- 1 sherlockes 444 mar 12 11:44 archivo_4.txt

Ahora para realizar el reemplazo de las cadenas introduciremos el comando

M-x dired-do-query-replace-regexp
  • Cadena a buscar → \(#+\s-\)\(.+\)\(\s-#+\)
  • Cadena a reemplazar → \1\2

Realizaremos todos los reemplazos pulsando la tecla Y y posteriormente guardaremos los cambios mediante el comando C-x s.

Reemplazando en varios archivos de forma recursiva

¿Que pasa si no todos los archivos en los que necesitamos realizar la busqueda y reemplazo están en la misma carpeta sino que se encuentran en distintos dubdirectorios? Dired ya no es capaz de realizar esta función por lo que tenemos que dar un paso más alla y utilizar los paquetes Dired+ e Icicles que en los apartados siguientes explico como instalar en Emacs.

En primer lugar abriremos mediante Dired con el comando C-x d para la ubicación donde tenemos los archivos “*.md” y los directorios en los que queremos buscar de forma recursiva.

Marcaremos manualemte mediante m los directorios en los que deseemos buscar

Ejecutamos el comando diredp-insert-subdirs-recursive para que se muestre en el buffer todos los archivos contenidos en los diredtorios marcados.

Ahora seleccionamos los archivos “*.md” mediante el comendo diredp-mark-extension-recursive e introducimos la extensión “md”.

Para que el buffer quede más limpio podemos ocultar los archivos que no están seleccionados mediante el comando diredp-omit-unmarked y ya sólo veremos en el buffer los archivos que necesitamos modificar junto con su correspondiente directorio.

  /home/sherlockes/Descargas/tmp:
  total used in directory 24K available 77081412
* -rw-rw-r-- 1 sherlockes  353 mar 13 10:55 archivo_1.md
* -rw-rw-r-- 1 sherlockes  435 mar 12 12:14 archivo_2.md
* -rw-rw-r-- 1 sherlockes  435 mar 12 12:24 archivo_3.md

  /home/sherlockes/Descargas/tmp/prueba_2:
  total used in directory 16K available 77081396
* -rw-rw-r-- 1 sherlockes 353 mar 13 10:55 archivo_1.md
* -rw-rw-r-- 1 sherlockes 435 mar 12 12:14 archivo_2.md
* -rw-rw-r-- 1 sherlockes 435 mar 12 12:24 archivo_3.md

Por alguna razón que desconozco fui capaz de hacer varias veces esta selección mediante el comando diredp-mark-files-regexp-recursive introduciendo la cadena “.md$” a buscar. Pero ahora Emacs no me ofrece la opción sin previamente insertar en el buffer todos los subdirectorios.

Ahora ya podemos ejecutar el comando que nos busque la cadena que queremos reemplazar de forma recursiva en todos los archivos que hemos marcado previamente.

diredp-do-query-replace-regexp-recursive

A continuación confirmaremos mediante “y” que queremos actuar sobre todos los archivos que tenemos marcados e introducimos la cadena a buscar y la de reemplazo

  • Cadena a buscar → \(#+\s-\)\(.+\)\(\s-#+\)
  • Cadena a reemplazar → \1\2

Volvemos a marcar con “y” que queremos realizar la operación en todos los archivos marcados y posteriormente con “Y” ejecutaremos los cambios en todos.

Para terminar guardaremos los cambios en todos los archivos mediante C-x s y pulsando a continuación la tecla “!”

Instalando Dired+

Para instalar Dired+ en Emacs sólo hay que descargar la librería “dired+.el” y añadir las siguiente líneas a nuestro archivo de configuración “.emacs”

(add-to-list 'load-path "~/dotfiles/emacs/.emacs.d/dired+/")
(load "dired+.el")
(require 'dired+)

En mi caso tengo ubicados los archivos de configuración dentro de la carpeta “dotfiles” y es ahí donde he guardado la librería. En posible guardarlo en otro sitio cambiando también la ruta en el archivo de configuración.

Instalando Icicles

Para instalar Icicles tenemos que seguir el mismo procedimiento que en el caso de Dired+ con una pequeña diferencia y es que en este caso no es un solo archivo sino que son varios y hay varios métodos para descargarlos tal y como se explica aquí. Personamente (Desde Linux Mint) he creado una carpeta “icicles” junto a la ya creada anteriormente “dired+” y dentro de ella he ejecutado el siguiente comando en la terminal.

wget https://www.emacswiki.org/emacs/download/icicles{,-chg,-cmd1,-cmd2,-doc1,-doc2,-face,-fn,-mac,-mcmd,-mode,-opt,-var}.el

Además, en el archivo de configuració de Emacs he añadido las siguientes líneas

(add-to-list 'load-path "~/dotfiles/emacs/.emacs.d/icicles/")
(require 'icicles)
(icy-mode 1)

Enlaces de interés