Todo acerca de cómo utilizar expresiones regulares en calibre

Las expresiones regulares son funciones utilizadas en muchos lugares en calibre para llevar a cabo sofisticadas manipulaciones de contenido y metadatos de libros electrónicos. Este cursillo es una breve introducción al uso de expresiones regulares en calibre.

Primero, una advertencia y unas palabras de aliento

Esto, inevitablemente, va a ser un poco técnico, después de todo, las expresiones regulares son una herramienta técnica para hacer cosas técnicas. Voy a tener que usar una jerga y conceptos que pueden parecer complicados o enrevesados. Voy a tratar de explicar esos conceptos tan claramente como pueda, pero realmente no puedo hacerlo sin utilizarlos en absoluto. Dicho esto, no se desanime por la jerga según intento explicar las cosas nuevas. Y mientras que las expresiones regulares en sí pueden parecer magia negra y arcana (o, siendo más prosaicos, una serie aleatoria de letras y signos sin sentido), le aseguro que no son tan complicadas. Incluso los que entienden las expresiones regulares muy bien tienen problemas para leer las más complejas, pero escribirlas no es tan difícil: se va construyendo la expresión paso a paso. Dicho esto, dé el primer paso y aventúrese conmigo en lo desconocido.

¿Dónde puedo utilizar expresiones regulares en calibre?

Las expresiones regulares se usan en unos cuantos lugares de calibre. En Buscar y sustituir, en las opciones de conversión, en la detección de metadatos a partir de los nombres de archivo en las configuraciones de importación y en buscar y sustituir al modificar metadatos en masa. El editor de libros de calibre también puede usar expresiones regulares en Buscar y sustituir. Por último, puede usar expresiones regulares al buscar en la lista de libros de calibre y en el visor de libros electrónicos de calibre.

¿Pero qué es una expresión regular?

Una expresión regular es una manera de describir porciones de texto. Una sola expresión regular puede coincidir con una serie de diferentes textos. Esto es lo que hace a las expresiones regulares tan potentes: son una forma concisa de describir un número potencialmente elevado de variaciones.

Nota

Aquí se habla de textos en el sentido en que se usan en los lenguajes de programación: un texto de uno o más caracteres, caracteres que incluyen caracteres reales, números, puntuacion y los llamados espacios en blanco (tabulaciones, saltos de línea, etc.). Tenga en cuenta que en general, los caracteres en mayúsculas y en minúsculas no se consideran iguales, por lo tanto «a» es diferente de «A», etc. En calibre, las expresiones regulares no distinguen mayúsculas y minúsculas en la barra de búsqueda, pero sí en las opciones de conversión. Hay una manera de hacer que las expresiones regulares no distingan nunca entre mayúsculas y minúsculas, pero hablaremos de eso más adelante. La cosa se complica porque las expresiones regulares permiten variaciones en los textos con los que coinciden, de manera que una expresión pueden coincidir con varios textos, que es la causa por la mucha gente no se molesta en usarlas. Más sobre esto en un momento.

¿Me lo puede explicar?

Bueno, para eso estamos aquí. En primer lugar, éste es el concepto más importante en las expresiones regulares: Un texto por sí mismo es una expresión regular que coincide consigo mismo. Es decir, si yo quisiera encontrar el texto "¡Hola a todos!" utilizando una expresión regular, ésta sería ¡Hola a todos!. Y sí, realmente es así de simple. Se dará cuenta, sin embargo, de que esto sólo coincide con el texto exacto "¡Hola a todos!" y no, por ejemplo, con "¡Hola a Todos!" u "¡hola a todos!" o cualquier otra variación.

No suena tan mal. ¿Qué viene después?

Lo que viene después es lo bueno de verdad. ¿Recuerda cuando dije que las expresiones regulares pueden coincidir con varios textos? Aquí se pone un poco más complicado. Digamos, como un ejercicio un poco más práctico, que un libro que quiere convertir tiene un incómodo pie de página con el número de páginas, como «Página 5 de 423». Obviamente, el número de página variará entre 1 y 423, así que deberá buscar 423 textos diferentes, ¿no? Pues no: las expresiones regulares permiten definir conjuntos de caracteres que coinciden: para definir un conjunto, ponga todos los caracteres del conjunto entre corchetes. Así, por ejemplo, el conjunto [abc] coincidirá con los caracteres «a», «b» o «c». Los conjuntos sólo coincidirán con uno de los caracteres del conjunto. Los conjuntos «entienden» gamas de caracteres, es decir, si quisiera hacer coincidir todos los caracteres en minúsculas, tendría que utilizar el conjunto de minúsculas [a-z] y para mayúsculas o minúsculas tendría que utilizar [a-zA-Z], etc. ¿Comprendido? Por lo tanto, usando la expresión Página [0-9] de 423 podrá seleccionar las primeras 9 páginas, reduciendo así las expresiones necesarias a tres. La segunda expresión Página [0-9][0-9] de 423 coincidirá con todos los números de página de dos dígitos, y seguro que puede adivinar cuál sería la tercera expresión. Sí, adelante, escríbala.

¡Estupendo! ¡Esto empieza a tener sentido!

Esperaba que dijera eso. Pero prepárese, ¡ahora se pone aún mejor! Acabamos de ver que con el uso de conjuntos, podemos detectar uno de varios caracteres a la vez. Pero incluso se puede repetir un carácter o conjunto, reduciendo la cantidad de expresiones necesarias para el ejemplo anterior de los números de página a una. Sí, ¡UNA! ¿Entusiasmado? ¡Debería estarlo! Funciona así: Algunos de los llamados caracteres especiales, «+», «?» y «*», repiten el elemento único que los precede. (Elemento significa un único carácter, un conjunto de caracteres, una secuencia de escape o un grupo —aprenderemos más acerca de los dos últimos más adelante—, en resumen, cualquier entidad individual en una expresión regular). Estos caracteres se denominan comodines o cuantificadores. Para ser más precisos, «?» coincide con 0 o 1 copias del elemento anterior, «*» coincide con 0 o más copias del elemento anterior y «+» coincide con 1 o más copias del elemento anterior. Algunos ejemplos: La expresión a? coincidiría con «» (que es un texto vacío, no estrictamente útil en este caso) o «a», la expresión a* coincidiría con «», «a», «aa» o cualquier número de aes seguidas y, finalmente, la expresión a+ coincidiría con «a», «aa» o cualquier número de aes seguidas. (Nota: ¡no coincide con el texto vacío!). Lo mismo ocurre con los conjuntos: La expresión [0-9]+ coincidiría con ¡cualquier número entero! Sé lo que está pensando, y tiene razón: si lo utiliza en el caso anterior de los números de página, ¿no sería la forma de obtener una única expresión que coincida con todos los números de página? ¡Sí, la expresión Página [0-9]+ de 423 coincidiría con cualquier número de página de ese libro!

Nota

Un apunte sobre estos cuantificadores: Generalmente intentan hacer coincidir tanto como sea posible, así que tenga cuidado al usarlos. Esto se conoce como «comportamiento codicioso», seguro que entiende por qué. Se vuelve problemático cuando, por ejemplo, se intenta hacer coincidir una etiqueta. Consideremos, por ejemplo, el texto "<p class="calibre2">Título aquí</p>" y digamos que le gustaría hacer coincidir la etiqueta de apertura (la parte entre el primer par de ángulos, veremos más sobre las etiquetas más adelante). Se podría pensar que la expresión <p.*> se correspondería con esa etiqueta, pero en realidad ¡coincide con todo el texto! (El carácter «.» es otro carácter especial, coincide con cualquier cosa excepto saltos de línea, por lo que, básicamente, la expresión .* coincide con cualquier línea que se pueda imaginar). En lugar de eso, trate de usar <p.*?>, lo que hace al cuantificador «*» no codicioso. Esa expresión sólo coincidiría con la primera etiqueta de apertura, como se pretende. De hecho, hay otra manera de lograr esto. La expresión <p[^>]*> coincidirá con la misma etiqueta de apertura, ya verá por qué después de la siguiente sección. Tenga en cuenta que frecuentemente hay más de una manera de escribir una expresión regular.

Bien, estos caracteres especiales están muy bien, pero ¿qué ocurre si quiero hacer coincidir un punto o un signo de interrogación?

Por supuesto que puede hacerlo: simplemente escriba una barra invertida delante de cualquier carácter especial y se interpretará como un carácter literal, sin ningún significado especial. Esta pareja de barra invertida y un carácter se llama secuencia de escape, y el acto de poner una barra invertida delante de un carácter especial se llama escapar ese carácter. Una secuencia de escape se interpreta como un solo elemento. Hay, por supuesto, secuencias de escape que hacen más que sólo escapar caracteres especiales, por ejemplo "\t" representa una tabulación. Vamos a ver algunas de las secuencias de escape más adelante. Ah, por cierto, en relación con esos caracteres especiales: considere que cualquier carácter que señalemos en esta introducción como poseedor de alguna función es especial y por lo tanto necesita ser escapado si desea que sea un carácter literal.

¿Y cuáles son los conjuntos más útiles?

Sabía que lo preguntaría. Algunos conjuntos útiles son [0-9], que coincide con un solo dígito, [a-z], que coincide con una sola letra minúscula, [A-Z], que coincide con una sola letra mayúscula, [a-zA-Z], que coincide con una sola letra, y [a-zA-Z0-9], que coincide con una sola letra o número. También puede utilizar una secuencia de escape como abreviatura:

\d

equivale a [0-9]

\w

equivale a [a-zA-Z0-9_]

\s

equivale a cualquier espacio en blanco

Nota

«Espacio en blanco» es un término para cualquier cosa que no se imprime. Estos caracteres incluyen el espacio, tabulador, avance de línea, salto de página, retorno de carro, espacios duros, etc.

Nota

Los caracteres de mayúsculas y minúsculas pueden coincidir con mayúsculas y minúsculas si está habilitada la configuración para hacer que las búsquedas no distingan entre mayúsculas y minúsculas. Esta configuración se encuentra, por ejemplo, en Preferencias > Búsqueda en calibre y en el panel de búsqueda en el Visor de libros electrónicos, así como en la herramienta :guliabel:`Modificar libro`.

Como último apunte sobre los conjuntos, también puede definir un conjunto como cualquier carácter excepto los especificados. Esto se hace incluyendo el carácter "^" como el primer carácter en el conjunto. Así, [^a] coincidirá con cualquier carácter excepto «a». Esto se llama complementar el conjunto. Las secuencias de escape anteriores que funcionan como abreviaturas también pueden complementarse. "\D" significa cualquier carácter que no sea un número, siendo por lo tanto equivalente a [^0-9]. Las otras abreviaturas se pueden complementar, como puede imaginar, utilizando la respectiva letra mayúscula en lugar de la minúscula. Volviendo al ejemplo <p[^>]*> de la sección anterior, ahora se puede ver que el conjunto especificado trata de coincidir con cualquier carácter excepto el ángulo de cierre.

Pero si tengo varios textos diferentes para hacer coincidir, ¿las cosas se complican?

No tema, todo sigue siendo bueno, bonito y barato. Considere este ejemplo: El libro que quiere convirtir tiene un «Título» escrito en cada página impar y «Autor» en cada página par. Queda muy bien en la versión impresa, ¿no? Pero en libros electrónicos es molesto. Puede agrupar expresiones enteras en paréntesis normales, y el carácter "|" hará que coincida la expresión a la derecha o la de la izquierda. Combínelas y ya está. ¿Demasiado rápido? Bueno, en primer lugar, agrupamos las expresiones para páginas pares e impares, consiguiendo de este modo (Título)(Autor) como nuestras dos expresiones necesarias. Ahora hacemos las cosas más simples mediante el uso de la barra vertical ("|" se llama barra vertical). Si utiliza la expresión (Título|Autor) hará coincidir «Título» (en las páginas impares) o «Autor» (en las páginas pares). Bueno, ha sido fácil, ¿no?

También puede, por supuesto, usar la barra vertical sin utilizar paréntesis de agrupamiento. ¿Recuerda cuando dije que los cuantificadores repiten el elemento que los precede? Pues bien, la barra vertical funciona de manera un poco diferente. La expresión Título|Autor también coincide con el texto «Título» o el texto «Autor», igual que el ejemplo anterior utilizando agrupamiento. La barra vertical selecciona entre toda la expresión anterior y toda la posterior. Así que, si quiere que coincidan los textos «Calibre» y «calibre» y quiere seleccionar sólo entre la «c» mayúscula y minúscula, tendría que utilizar la expresión (c|C)alibre, donde el agrupamiento asegura que sólo la «C» se selecciona. Si usara c|Calibre, obtendría coincidencias con el texto «c» o el texto «Calibre», que no es lo que quería. En resumen: en caso de duda, utilice el agrupamiento con la barra vertical.

Falta algo…

…espere un momento, hay una última cosa muy interesante que se puede hacer con los grupos. Si tiene un grupo que previamente ha hecho coincidir, puede utilizar referencias a ese grupo posteriormente en la expresión. Los grupos se numeran comenzando por 1, y se referencian escapando el número del grupo, por ejemplo, al quinto grupo se haría referencia como \5. Así, aplicando ([^ ]+) \1 sobre el texto «Prueba Prueba», ¡se haría coincidir todo el texto!

¿No dijo al principio que hay una manera de hacer que una expresión regular no distinga entre mayúsculas y minúsculas?

Sí, lo hice, gracias por prestar atención y recordármelo. Puede decirle a calibre cómo desea que se comporten ciertos aspectos mediante el uso de opciones. Las opciones se incluyen en una expresión mediante la construcción especial (?aquí van las opciones), donde, obviamente, debe sustituir «aquí van las opciones» por las opciones específicas que desee. Para no distinguir mayúsculas y minúsculas, la opción es i, así que incluya (?i) en la expresión. Por lo tanto, (?i)prueba coincidiría con «Prueba», «pRueba», «PRueba» y cualquier variación en las mayúsculas y minúsculas que pueda imaginar.

Otra opción útil hace que el punto coincida con absolutamente cualquier carácter, incluyendo el salto de línea, la opción s. Si desea utilizar varias opciones en una expresión, sólo hay que ponerlas en la misma declaración: (?is) no distingue entre mayúsculas y minúsculas y hace que el punto coincida con todo. No importa qué opción se declara en primer lugar, (?si) sería equivalente a lo anterior.

Creo que empiezo a entender esto de las expresiones regulares… ¿cómo las utilizo en calibre?

Conversiones

Vamos a empezar con las configuraciones de conversión. En la sección Buscar y sustituir, puede introducir una regexp (abreviatura de expresión regular) que describe el texto que se sustituirá durante la conversión. La parte interesante es el asistente. Pulse en la varita mágica y obtendrá una vista previa de lo que calibre «ve» durante el proceso de conversión. Vaya al texto que desea eliminar, selecciónelo y cópielo, péguelo en el campo de expresión regular en la parte superior de la ventana. Si hay partes variables, como números de página o algo así, use conjuntos y cuantificadores para recogerlos, y ya que está en ello, recuerde que debe escapar los caracteres especiales, si hay alguno. Pulse el botón con la etiqueta Probar y calibre resaltará las partes que sustituiría al utilizar la expresión regular. Una vez que esté satisfecho, pulse «Aceptar» y se inicia el proceso de conversión. Tenga cuidado si el origen de la conversión tiene etiquetas como este ejemplo:

Maybe, but the cops feel like you do, Anita. What's one more dead vampire?
New laws don't change that. </p>
<p class="calibre4"> <b class="calibre2">Generated by ABC Amber LIT Conv
<a href="http://www.processtext.com/abclit.html" class="calibre3">erter,
http://www.processtext.com/abclit.html</a></b></p>
<p class="calibre4"> It had only been two years since Addison v. Clark.
The court case gave us a revised version of what life was

(copiado descaradamente de este hilo). Habría que eliminar también algunas de las etiquetas. En este ejemplo, recomendaría empezar con la etiqueta <b class="calibre2">, tiene que acabar con la etiqueta de cierre correspondiente (las etiquetas de apertura son <etiqueta>, las etiquetas de cierre son </etiqueta>), que es simplemente el siguiente </b> en este caso. (Consulte un buen manual de HTML o pregunte en el foro si tiene dudas sobre este punto). La etiqueta de apertura puede describirse usando <b.*?>, la etiqueta de cierre usando </b>, por lo que podríamos quitar todo lo que está entre estas etiquetas usando <b.*?>.*?</b>. Pero usar esta expresión sería una mala idea, ya que elimina todo lo encerrado entre las etiquetas <b> (que, por cierto, hacen que el texto encerrado se muestre en negrita), y es casi seguro que eliminaremos porciones del libro de esta manera. En su lugar, incluya también el principio del texto entre las etiquetas, haciendo la expresión regular <b.*?>\s*Generated\s+by\s+ABC\s+Amber\s+LIT.*?</b>. La \s con cuantificadores se incluye aquí en lugar de utilizar explícitamente los espacios que aparecen en el texto para recoger cualquier variación del texto que pudiera ocurrir. Si prueba una nueva expresión, recuerde revisar qué eliminará calibre para asegurarse de que no elimina partes que desea conservar. Si sólo examina un caso, es posible que pase por alto un desajuste en otro lugar del texto. También tenga en cuenta que en caso de que accidentalmente elimine más o menos etiquetas de las que realmente deseaba, calibre intenta reparar el código dañado después de hacer la eliminación.

Añadir libros

También puede utilizar expresiones regulares para extraer metadatos de los nombres de archivo. Puede encontrar esta función en la sección «Añadir libros» de la configuración. Hay una característica especial: puede utilizar nombres de campo para los campos de metadatos, por ejemplo (?P<title>), que indicaría que calibre utiliza esta parte del texto como el título del libro. Los nombres de los campos permitidos se enumeran en las ventanas, junto con otro útil campo de prueba. Un ejemplo: digamos que desea importar un gran número de archivos llamados así Textos clásicos: La divina comedia de Dante Alighieri.mobi (obviamente, ya lo tiene en la biblioteca, ya que a todos nos gusta la poesía italiana clásica) o Ciencia ficción épica: La Trilogía de la Fundación de Isaac Asimov.epub. Esto es obviamente un esquema de nombres del que calibre no va a extraer datos significativos: la expresión estándar para la extracción de los metadatos es (?P<title>.+) - (?P<author>[^_]+). Una expresión regular que podría funcionar en este caso sería [a-zA-Z]+: (?P<title>.+) de (?P<author>.+). Tenga en cuenta que, dentro del grupo para el campo de metadatos, es necesario utilizar expresiones para describir lo que el campo realmente recoge. Y también tenga en cuenta que, cuando se utiliza el campo de prueba que calibre ofrece, es necesario agregar la extensión de archivo al nombre de archivo de prueba, de lo contrario no recibirá ninguna correspondencia en absoluto, a pesar de utilizar una expresión correcta.

Modificar metadatos en masa

La última parte es Buscar y sustituir con expresiones regulares en los campos de metadatos. Puede acceder a esta función seleccionando varios libros en la biblioteca y usando la modificación de metadatos en masa. ¡Tenga mucho cuidado al utilizar esta última función, ya que puede hacer cosas muy malas en la biblioteca! Verifique que las expresiones hacen lo que quiere que hagan en los campos de prueba, y sólo marque los libros que realmente quiere cambiar. En el modo de búsqueda de expresiones regulares, puede buscar en un campo, sustituir el texto con algo e incluso escribir el resultado en otro campo. Un ejemplo práctico: Digamos que la biblioteca contiene los libros de la serie Dune de Frank Herbert, nombrados de este modo Dune 1 - Dune, Dune 2 - El mesías de Dune y así sucesivamente. Ahora desea incluir Dune en el campo serie. Puede hacerlo mediante la búsqueda (.*?) \d+ - .* en el campo título y sustituyendo con \1 en el campo serie. ¿Ve lo que he hecho? Esto es una referencia al primer grupo de coincidencia en la expresión regular. Ahora que tiene toda la serie lista, sólo tiene que hacer otra búsqueda .*? - en el campo título y reemplazarlo con "" (un texto vacío), de nuevo en el campo título, y los metadatos estarán todos limpios y ordenados. ¿No es genial? Por cierto, en lugar de sustituir todo el campo, puede también añadir al principio o al final del campo, por lo que, si quisiera el título del libro con la información de la serie delante, puede hacerlo también. Como sin duda se ha dado cuenta, hay una casilla etiquetada Distinguir mayúsculas, para que no tenga que usar la opción correspondiente dentro de la expresión regular en este caso.

Bueno, casi llegamos a la conclusión de la muy breve introducción a las expresiones regulares. Esperemos que le haya mostrado lo suficiente como para, al menos, comenzar y seguir aprendiendo por sí mismo. Un buen punto de partida sería la documentación Python para expresiones regulares.

Unas últimas palabras de advertencia: las expresiones regulares son potentes, pero también es muy fácil equivocarse. calibre ofrece muy buenas posibilidades de pruebas para ver si las expresiones se comportan como se espera que lo hagan. Úselas. Intente no dispararse a los pies (me encanta esta expresión…). Pero si, a pesar de la advertencia, se lesiona el pie (o cualquier otra parte del cuerpo), trate de aprender de ello.

Referencia rápida

Créditos

Gracias por ayudar con sugerencias, correcciones y demás:

  • ldolse

  • kovidgoyal

  • chaley

  • dwanthny

  • kacir

  • Starson17

  • Orpheu

Para más información sobre expresiones regulares, véase The Python User Manual (en inglés). El motor de expresiones regulares usado por calibre es en realidad regex, que añade varias mejoras sobre el estándar de Python.