Nota: Esta guía fue publicada en el año 2015 en la antigua web de NVDA en español. La versión que se ofrece a continuación ha sido actualizada solucionando errores producidos por la conversión entre lenguajes de marcado, eliminando algunos fallos ortográficos y gramaticales del autor y cambiando la referencia al apartado de la guía de usuario que habla de los diccionarios. Si detectas algún error, déjanos un comentario más abajo.

Como se explica en la sección 11.1.14 de Diccionarios del Habla en la Guía de Usuario, gracias a la creación o modificación de los diccionarios NVDA permite personalizar la forma en que el sintetizador lee ciertas palabras, símbolos o dígitos.

En esta pequeña guía vamos a ver como utilizar Expresiones regulares en los diccionarios del habla del lector de pantalla NVDA, ya que en la guía de usuario no se explican con detalle.

A continuación se muestra una breve introducción a las expresiones regulares, seguida de una lista de caracteres y secuencias especiales. No trates de memorizar estas listas, por ahora solo debes tener en cuenta que cada carácter y secuencia especial tiene su propio significado y función.

Con los ejemplos aprenderás a entender el funcionamiento y a crear tu propio diccionario con expresiones regulares.

¿Estás listo? ¡Vamos!

Expresiones regulares: conceptos básicos

En esta sección se presentan conceptos de expresiones regulares, y se explica cómo se crean y se utilizan en los diccionarios de voz de NVDA.

Una expresión regular, llamada también regex, es una secuencia de caracteres que forma un patrón de búsqueda, principalmente utilizada para la búsqueda de cadenas de caracteres y operaciones de sustitución.

Específicamente, NVDA va a aplicar Expresiones regulares para reemplazar patrones cada vez que se encuentre una coincidencia en la lectura.

Podemos decir que es una operación de sustitución cuando el texto escrito se reemplaza antes de ser procesado por el sintetizador de voz.

Las expresiones regulares pueden contener caracteres ordinarios y caracteres especiales.

Los caracteres ordinarios son las letras de la a a la z, los números, el signo subrayado y otros signos de puntuación que no están incluidos en los caracteres especiales.

La mayoría de los caracteres ordinarios, como “a A b 9 0”, son las expresiones regulares más simples, simplemente coinciden consigo mismos.

Por ejemplo, se pueden concatenar caracteres ordinarios así:

la expresión “Odissea2001” coincide con “Odissea2001”.

Caracteres Especiales

Lista completa de caracteres especiales y su comportamiento en el contexto de las expresiones regulares:

  • “\”. Marca el siguiente caracter como un caracter especial, un literal, una referencia inversa. Por ejemplo, “r” coincide con el caracter “r”, mientras que “\r” coincide con un caracter de retorno de carro. Cuando precede a caracteres que normalmente se tratan de forma especial, indica que el siguiente caracter no es especial y debe ser interpretado literalmente. Por ejemplo, la secuencia \” coincide con ” y ( coincide con (.
  • “.”. Coincide con cualquier caracter excepto con “\n”.
  • “^”. Coincide con la posición al principio de la cadena de entrada. La propiedad Multiline está establecida para coincidir también con la siguiente posición después de “\n” o “\r”. Es decir, este caracter corresponde también a la posición inmediatamente después de una nueva línea o un retorno de carro.
  • “$”. Coincide con la posición al final de la cadena de entrada. La propiedad Multiline está establecida para que $ coincida también con la posición anterior a “\n” o “\r”.
  • “?”. Cuando este caracter va inmediatamente después de cualquier otro cuantificador (se mencionan a continuación), el modelo coincidente es no expansivo. Un modelo no expansivo coincide lo menos posible con la cadena buscada, mientras que el modelo expansivo predeterminado coincide tanto como sea posible con la cadena buscada.
  • “?”. Un cuantificador,coincide una vez o ninguna con el caracter o subexpresión anterior. Equivale a {0,1}
  • “*”. Un cuantificador, coincide cero o más veces con el caracter o subexpresión anterior. Equivale a {0,N}.
  • “+”. Un cuantificador, coincide una o más veces con el caracter o subexpresión anterior. Equivale a {1,N}.
  • “{n}”. Un cuantificador: coincide exactamente n veces, donde n es un entero no negativo. Por ejemplo, “o{2}” no coincide con la ‘o’ de “soy”, pero coincide con las dos oes de “Cooperar”.
  • “{n,}”. Un cuantificador: coincide como mínimo n veces, donde n es un entero no negativo. Por ejemplo, “o{2,}” coincide con todas las oes de “nooooo”, pero no coincide con la “o” de “sol”.
  • “{n,m}”. Un cuantificador. M y n son enteros no negativos donde n es menor o igual de m. Coincide n veces como mínimo y m veces como máximo. Tener en cuenta que no se puede incluir un espacio entre la coma y los números.
  • “[xy]”. Un juego de caracteres, coincide con cualquiera de los caracteres incluidos entre corchetes. Por ejemplo, “[aeu]” coincide con “a” en “Madrid”.
  • “[^xy]”. Un juego de caracteres negativo. Coincide con cualquier caracter no incluido entre corchetes. Por ejemplo, “[^aeu]” coincide con la “M”, la”d”, la “r”, la “d” de “Madrid”, pero no coincide con la “a”.
  • “[a-z]”. Un intervalo de caracteres, coincide con cualquier caracter del intervalo especificado. Por ejemplo, “[a-z]” coincide con cualquier caracter alfabético en minúsculas dentro del intervalo de la ‘a’ a la ‘z’.
  • “[^a-z]”. Caracteres de un intervalo negativo. Es decir, coincide con cualquier caracter que no esté incluido en el intervalo especificado. Por ejemplo, “[^a-z]” coincide con cualquier caracter que no esté incluido en el intervalo de la ‘a’ a la ‘z’.
  • “|” Es un carácter disyuntivo: x|y, coincide con x o con y. Por ejemplo, la expresión “Juli(a|o)” coincide con “Julia” o con “Julio”.
  • “(…)”. Una subexpresión que coincide con el modelo entre paréntesis y captura la coincidencia. La coincidencia capturada se puede recuperar en el remplazo mediante las secuencias especiales “\1” “\2” etc. Para que coincidan los paréntesis ( ), utilice “(” o “)”.
  • “(?:…)”. Una subexpresión que coincide con el modelo entre los paréntesis, pero que no captura la coincidencia, es decir, la coincidencia no se almacena para un posible uso posterior. La expresión “(?:\d+)(Salir)” coincide con la palabra “Salir” después de un conjunto de números en una cadena como por ejemplo “123456Salir Gráfico Enlace”. Nota, los números no se almacenan y además no serán procesados por el sintetizador. El sintetizador simplemente ignora el contenido de esta Afirmación. Esta subexpresión se considera como grupo de cadena irregular, No se utiliza mucho en los diccionarios.
  • “(?=…)”. Una subexpresión que realiza una búsqueda anticipada positiva, la cual coincide con la cadena en cualquier punto donde empiece una cadena que coincida con el modelo entre los paréntesis. Por ejemplo, “Juli(?=a|o)” coincide con “Juli” en “Julia” pero no con “Juli” en “Juliu”. Ésta es una coincidencia sin captura, es decir, la coincidencia no se captura para un posible uso posterior. Las búsquedas anticipadas no consumen caracteres, es decir, después de que se produce una coincidencia, la búsqueda de la siguiente comienza inmediatamente después de la última coincidencia, no después de los caracteres que componen la cadena de búsqueda anticipada.
  • “(?!…)”. Una subexpresión que realiza una búsqueda anticipada negativa, la cual coincide con la cadena de búsqueda en cualquier punto donde empiece una cadena que no coincida con el modelo. Por ejemplo, “Juli(?!e|u)” coincide con “Juli” en “Julia” pero no coincide con “Juli” en “Julie”. Ésta es una coincidencia sin captura, es decir, la coincidencia no se captura para un posible uso posterior. Las búsquedas anticipadas no consumen caracteres, es decir, después de que se produce una coincidencia, la búsqueda de la siguiente comienza inmediatamente después de la última coincidencia, no después de los caracteres que componen la cadena de búsqueda anticipada.
  • “(?<=…)”. Afirmación look-behind positiva, es decir, es válida la siguiente expresión sólo si la condición del modelo entre paréntesis se verifica. Por ejemplo, “(?<=0)\d” coincide con cualquier número precedido por cero. Las afirmaciones son sin captura, es decir, no se captura para un posible uso posterior.
  • “(?<!…)”. Afirmación look-behind no positiva, es decir, es válida la siguiente expresión sólo si la condición del modelo entre paréntesis no se verifica. Por ejemplo, “(?<![1-9])\d” coincide con cualquier número que no está precedido por un número comprendido entre 1 y 9.

Secuencias Especiales

Las secuencias especiales consisten en “\” y un caracter ordinario como en la lista de abajo. Si el caracter ordinario no está en la lista, entonces la expresión resultante coincidirá con el segundo caracter.

  • “\A”. Coincide sólo en el inicio de la cadena.
  • “\Z”. Coincide sólo con el final de la cadena.
  • “\b”. Coincide con el límite de una palabra. Es decir, la posición entre una palabra y un espacio. Por ejemplo, “ir\b” coincide con ‘ir’ en “mentir”, pero no coincide con ‘ir’ en “mentira”.
  • “\B”. Coincide con una posición que no es un límite de palabra. La expresión “ir\B” coincide con “ir” en “mentiras”, pero no coincide con “ir” en “mentir”.
  • “\d”. Coincide con un dígito. Equivale a “[0-9]”.
  • “\D”. Coincide con un caracter que no sea un dígito. Equivale a “[^0-9]”.
  • “\s”. Coincide con cualquier caracter de espacio en blanco incluidos espacio, tabulación, salto de página, etc. Equivale a “[\f\n\r\t\v]”.
  • “\S”. Coincide con cualquier caracter que no sea un espacio en blanco. Equivale a “[^\f\n\r\t\v]”.
  • “\w”. Coincide con cualquier caracter alfanumérico incluido el subrayado. Equivale a “[A-Za-z0-9_]”.
  • “\W”. Coincide con cualquier caracter que no pertenezca a los caracteres alfanuméricos. Equivale a “[^A-Za-z0-9_]”.

Ejemplos

Finalmente llegamos a la parte práctica con los ejemplos.

Por conveniencia usaremos un diccionario temporál en los ejemplos. Para ello, necesitamos ajustar la opción para las expresiones regulares desde el diálogo correspondiente.

Ejemplo 1

El sintetizador eSpeak en español pronuncia con C suave palabras extranjeras que comienzan con “ch”, como Christ, christmass, Christofer o Christopher, Christian, etc. Si deseamos escuchar una pronunciación mejor, podemos usar la siguiente expresión regular, muy sencilla.

Patrón: “\bChri\B”

Reemplazar: “Cri”

Explicación: la secuencia especial “\b” marca el inicio de la palabra, mientras que la secuencia “\B” (la B mayúscula) dice que en esta posición no hay limite de palabra.

Cada vez que se encuentra el prefijo “Chri” en el texto, el sintetizador lee el texto indicado en el Reemplazo “Cri”.

Tener en cuenta que las secuencias especiales \b y \B son marcadores de posición, no necesitan una recuperación en el reemplazo.

La mayoría de las secuencias especiales, como por ejemplo \s, \w, \d, necesitan ser recuperadas en el reemplazo, si no vamos a recuperarlas no se envierán al sintetizador.

Ejemplo 2

A veces puede ser útil leer el nombre de unidades de medida cuando en el texto aparecen como abreviaturas.

Por ejemplo, 1ml 12 ml. ¿no sería fantástico que el sintetizador las leyera así?

Un mililitro y doce mililitros.

Necesitamos dos expresiones regulares para distinguir el plural y el singular.

Primera expresión regular.

Patrón: “(^|\s)1[ ]?ml\b”

Reemplazar: “\1un mililitro”

Segunda expresión:

Patrón: “(?<=\d)[ ]?ml\b”.

Reemplazar: ” Mililitros”.

Explicación: la primera subexpresión “(^|\s)” tiene en cuenta si la posición está al principio o si hay un espacio antes del número 1.

Esta subexpresión se puede recuperar en el remplazo mediante la secuencia especial \1.

Recuerda que las subexpresiones regulares entre paréntesis, llamadas también grupos de cadena, se pueden recuperar en el remplazo con la secuencia especial correspondiente. Es decir, el primer grupo de cadena de izquierda a derecha se recupera con \1, el segundo con \2, etcétera. Después del grupo está el número 1, ya que estamos buscando en el texto 1ml o 1 ml, puede ser que haya o no un espacio entre el número y la abreviatura.

Entre corchetes se ha puesto un espacio, se pueden añadir distintos caracteres de espacio. Luego hay un cuantificador, cerrar interrogación, que indica que este espacio puede aparecer una vez o ninguna.

Finalmente, nuestra abreviatura ml y una secuencia especial “\b” para cerrar la expresión regular.

La secuencia al fin indica un límite de palabra, es decir que “ml\b” no puede coincidir por ejemplo con “mls” o “mla”.

La segunda expresión regular se abre con una aserción “(?<=\d), significa que nuestra expresión Es válida solo si hay un dígito antes.

La aserción usa una secuencia especial “\d” que coincide con cualquier número.

Entonces, ¿por qué no funciona si antes está solo el número 1?

Te toca adivinar la respuesta…

Ahora, gracias a las dos expresiones regulares, cuando “ml” es precedido por 1 o ningún caracter alfanumérico, el sintetizador lee “mililitro”. En los demás casos el sintetizador lee “mililitros”.

El orden es importante, las expresiones regulares más arriba Tienen prioridad y pueden cancelar las expresiones posteriores. Por eso la segunda expresiónSe inserta a continuación de la primera.

¿A qué estás esperando? Ahora trata de crear reglas para leer otras unidades como Kg, MB, m² o cm³.

Ejemplo 3

Todavía es común separar los millares, millones, etc., mediante un espacio Para facilitar la lectura de números cuando constan de más de cuatro cifras:

12 354 o 1 303 404.

Algunos sintetizadores no leen correctamente esta forma de escribir los números enteros, más adelante se explica cómo configurar una expresión regular para leerlos correctamente.

Abrimos un diálogo para crear nuestro diccionario del habla desde el menú Preferencias.

Necesitamos ajustar el patrón para comparar como expresión regular desde el botón de opción correspondiente, y rellenar el campo Patrón y el campo de reemplazar.

Patrón: “(?<=\d)([  ]?)(\d{3})”

reemplazar: “\2”

Vamos a explicar.

La primera afirmación indica que la búsqueda es cierta si hay un dígito antes de la cadena. Sigue una subexpresión entre paréntesis con un conjunto de espacios dentro, son tres signos distintos de espacio que se pueden encontrar.

Recuerda que solo uno de los caracteres entre corchetes coincide con la búsqueda, luego hay un cuantificador “?” para indicar que se puede encontrar cero o una sola vez. Sigue a la derecha otra subexpresión entre paréntesis que indica un número de tres dígitos. El cuantificador “{3}” significa que el dígito “\d” debe repetirse tres veces, ni más ni menos.

Vamos a ver lo que tenemos que insertar en el campo reemplazar.

La primera subexpresión “(?<=\d)” en el patrón es una afirmación, no se almacena para un posible uso en el remplazo. Esto no significa que no se tengan en cuenta los caracteres de esa afirmación, el sintetizador va a leer estos dígitos junto a los otros sin recuperar la subexpresión en el campo reemplazar.

El segundo grupo o subexpresión “([ ]?)” es una subexpresión regular y se puede recuperar en el remplazo mediante la secuencia especial \1. Pero nosotros queremos excluirlo, así que no lo recuperamos.

Por el contrario, vamos a recuperar la tercera subexpresión “(\d{3})” mediante la secuencia especial \2.

De esta manera enviamos al sintetizador un número sin espacios entre los dígitos.

Ejemplo 4

Cuando consultamos una lista de números de teléfono o algo similar, puede ser útil leer los números dígito a dígito.

Por ejemplo, si encontramos 3332211444 podríamos leerlo como si estuviera escrito “3 3 3 2 2 1 1 4 4 4”.

Necesitamos una secuencia especial en el patrón de búsqueda que encuentre o coincida con cualquier número, y luego añadir un espacio después de cada dígito sólo cuando es seguido por otro dígito.

Patrón: “(\d)(?=\d)”

Reemplazar: “\1 “.

En el reemplazo recuperamos el primer grupo “(\d)” con “\1”, e inmediatamente después hay un espacio. El patrón de búsqueda encuentra cualquier dígito solo si va seguido de otro dígito.

Este es un ejemplo de una expresión regular que se puede utilizar en determinados casos, pero la mayoría de las veces dá como resultado una lectura tediosa. Está bien para leer números de teléfono, pero no sería agradable leer por ejemplo “Son las 13:26”.

Como hemos visto, las expresiones regulares permiten encontrar un texto específico y reemplazarlo a nuestro gusto antes de enviarlo al sintetizador.

La mayoría de las veces es suficiente utilizar expresiones regulares simples, aunque debemos tener en cuenta que cuanto más simple sea la expresión regular, menos específica será la búsqueda.

Una sugerencia antes de concluir: no se deberían crear diccionarios del habla muy largos. Si el diccionario es demasiado grande puede ralentizar mucho el lector de pantalla. (1500 expresiones o más).

Además, no hay necesidad de corregir los errores de ortografía, o tratar de simular la pronunciación extranjera cuando el sintetizador no tiene los fonemas necesarios.

Autor: José Manuel Delicado Alcolea

Ingeniero de software y estudiante de máster en ingeniería informática en la Universidad Rey Juan Carlos. Me encanta todo lo relacionado con la informática, la accesibilidad y las nuevas tecnologías.

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.