Expresiones regulares y traducción (parte III)

¡Saludos a todos y feliz Navidad!

Ya se acerca el final del año 2012, que ha tenido sus más y sus menos, un año con bastantes cambios para mí, la verdad. Para cerrarlo y asimismo poner fin a la serie sobre expresiones regulares y traducción, en el siguiente post veremos los aspectos más avanzados del uso de las regexp que complementan a los operadores básicos vistos en los artículos anteriores de esta serie. Sin más dilación, vamos allá.

Ya sabemos cómo encontrar caracteres literales individuales, así como usar comodines para localizar tipos genéricos de caracteres, ahora es el momento de aprender a gestionar la repetición y el número de caracteres que queremos buscar. Como en los artículos anteriores, veamos una tabla de referencia con los patrones y metacaracteres de búsqueda correspondientes.

Patrones y metacaracteres para gestión de repeticiones

+ (signo más): al incluir el signo más tras una expresión regular, se encuentran uno o más caracteres de dicha regexp. Por ejemplo, mientras que [0-9] sirve para encontrar un número cualquiera entre 0 y 9, [0-9]+ sirve para encontrar uno o más números consecutivos.

* (asterisco): se usa exactamente igual que el anterior, solo que el asterisco sirve para encontrar cero o más repeticiones del carácter o rango de caracteres buscados con la regexp escrita.

? (signo de interrogación): se utiliza de forma parecida a los anteriores, con la salvedad de que ? sirve para encontrar cero o una repetición del carácter o rango de caracteres buscados.

{x} (corchetes): al crear un expresión regular seguida de corchetes con una cifra, especificamos el número exacto de ocurrencias de la regexp en cuestión que queremos encontrar. Por ejemplo, si ponemos “ {2}”, como resultado encontraremos todos los dobles espacios, pero únicamente los dobles (si hay tres espacios seguidos, no funcionará).

{x,y} (corchetes): cuando en un corchete usamos dos cifras separadas por una coma, estamos indicando un número mínimo (x) y máximo (y) de repeticiones que deseamos localizar.

{x,} (corchetes): al usar únicamente una cifra y una coma dentro del corchetes, especificamos el mínimo de repeticiones que se deben encontrar. Por ejemplo, si ponemos “ {2,}”, como resultado encontraremos todos los dobles espacios, espacios triples, cuádruples, etc.

Como podéis imaginar, al poder controlar con mucha más precisión la cantidad de caracteres que se recuperan para un intervalo o un único tipo de caracteres, tenemos mucha más potencia a nuestra disposición. Por ejemplo, si retomamos el ejemplo de la localización de números del artículo anterior, ahora podemos ver que dicha expresión podía mejorarse mucho. Así, en lugar de buscar \d\.\d (dígito, punto, dígito), ahora podríamos hacer algo como esto: \d+\.\d+ (uno o más dígitos, punto, uno más dígitos), o incluso precisarlo más con una regexp como \d+,\d{3}\.\d+ (uno o más dígitos – coma- tres dígitos – punto – uno o más dígitos) para buscar números con unidades de millar y decimales en formato de inglés británicos.

Una vez se conocen todos los operadores es cuestión de lo más complicado, es decir, exactamente lo que se comentó en el primer artículo de esta serie: definir bien qué queremos buscar (y eventualmente reemplazar) para así poder crear un patrón o expresión regular que lo represente exactamente.

Las subexpresiones

Tras ver todos los operadores, ahora me gustaría introducir otro concepto, el de las subexpresiones. Se trata sencillamente de usar paréntesis (como en matemáticas) para agrupar búsquedas y tratarlas como un único elemento. Por ejemplo, si en un texto se quieren buscar todos los años que empiecen por 18 o 19, podríamos usar la siguiente búsqueda: (18|19)\d{2}. De esta forma, buscaríamos en primer lugar 18 o 19 (¿se me olvidó mencionar que las regexp también permiten usar la barra vertical | como un operador booleano OR?) y, a continuación, exactamente dos dígitos cualquiera.Esta es en realidad una súper simplificación de todo lo que ofrecen las subexpresiones (siguiendo con el símil de la matemáticas, recordad los infinitos elementos anidados con paréntesis en las clases de álgebra), pero creo que suficiente para dejar claro cómo separar partes significativas de las regexp que creemos.

Bueno, creo que con esta introducción a los operadores para gestión de número de ocurrencias y las subexpresiones podemos dar por conceptualmente concluido este post (¡además se acaba el año 2012 y todavía tenemos muchas cosas que hacer!). Al combinar las nociones de los artículos anteriores y de este, prácticamente cualquier profesional que trabaje como traductor o localizador (en el sentido de la producción lingüística, que no de la preparación de archivos) podría ser capaz de crear expresiones complejas para crear controles de calidad personalizados, hacer búsquedas, filtrar el contenido de archivos, etc. Como ya he dicho anteriormente, el dominio de las expresiones regulares es cuestión de práctica, de cometer errores, de consultar regexp creadas por otros, comprenderlas y crecer desde ellas. Por ello, no puedo sino animaros a continuar practicando y usando las regexp en vuestro día a día para consolidar vuestros conocimientos.

No obstante, dado que en el sector de la traducción y la localización habitualmente las expresiones regulares se suelen utilizar también para la creación de definiciones de tipos de archivos y filtros personalizados para la extracción de cadenas de archivos y la preparación de archivos de traducción y localización, no puedo dar por zanjado este tema sin mencionar que obviamente quedarían por tocar temas como la anidación avanzada, uso de referencias a ocurrencias anteriores (backreferences), uso de operadores con alcance mínimo (lazy) o máximo (greedy), pseudo-variables, conversión entre mayúscula y minúscula, búsqueda contextual (hacia atrás/delante), uso de sentencias condicionales, etc. Se trata de conceptos bastante avanzados para los que en la mayoría de casos se requieren ciertas nociones de programación (para no perderse con las analogías, las referencias a lenguajes de programación, etc.). Por ello, y porque además me veo incapacitado para explicarlo todo con la seguridad y rigor necesarios (porque algunos conceptos no los tengo 100% manejados y cometo fallos), para los que queráis seguir avanzando con las expresiones regulares me gustaría recomendaros tres títulos: Mastering RegExp (O’Relly), Regular Expressions Cookbook (O’Relly) y Teach Yourself Regular Expressions In 10 Minutes (Ben Forta). Son parte del material bibliográfico con el que he ido aprendido y mejorando mi uso de las expresiones regulares. Por otra parte, también hay mucho material en la red.

brindisCon esta última nota bibliográfica llegamos al fin (al menos de momento) de la serie de artículos sobre expresiones regulares. Espero que os hayan resultado útiles y a que muchos os hayan animado a comenzar a utilizarlas. En serio, cuando uno se acostumbra a emplearlas a diario, acabo mejorando como profesional. Asimismo, con este post, llegamos también al fin del año 2012. Espero que a todos el 2013 os depare lo mejor.

Nos leemos en la blogosfera. ¡Feliz año nuevo!

Atentamente,

Álvaro

Recomendación musical: para terminar el año musical, un tema(zo) del disco del último mes que más me ha sorprendido (sobre todo por la juventud de su autor): Two Fingers de Jake Bugg.

Expresiones regulares y traducción (parte II)

Hola y saludos otoñales (casi invernales) a todos (los del hemisferio norte, en el sur, al revés):

En el anterior post de esta serie sobre expresiones regulares vimos la introducción general y el uso de los operadores básicos (caracteres literales, punto, corchetes, guión y acento circunflejo).

En esta segunda parte de la serie vamos a centrarnos en los caracteres con un significado especial más allá del propio literal: los metacaracateres. Los metacaracteres sirven para identificar o encontrar patrones de texto o formato que, de otra manera, resultaría bien imposible, bien muy complejo. En una implementación general de la sintaxis de las expresiones regulares nos encontramos con la siguiente selección de metacaracteres habituales, que presento en un cuadro para que pueda usarse como referencia rápida.

Metacaracteres de búsqueda

\ (barra invertida): la barra invertida sirve para anular (o “escapar” en términos informáticos) un metacaracter de forma que se utilice como un carácter literal. Por ejemplo, si hacemos una búsqueda por \\n (como veremos a continuación, \n es un metacaracter para un salto de línea manual) estaremos indicando que en lugar de buscar un salto de línea se busque el carácter de barra invertida seguido del carácter n (práctica habitual en programación para suprimir, por ejemplo, los saltos de línea y cambiarlos a otra cosa).

\f (barra invertida y f): sirve para identificar o buscar los caracteres de salto de página en formato electrónico (se trata de un carácter que manda la instrucción a la impresora).

\n (barra invertida y n): sirve para encontrar un carácter de salto de línea en un documento (de hecho, \n es la forma de insertar una línea nueva en muchos lenguajes de programación como C o C++).

\r (barra invertida y r): sirve para encontrar un carácter de retorno de carro (cuando se pulsa la tecla Intro para pasar la siguiente línea, como cuando se empujaba la palanca de cambio de línea en una máquina de escribir antigua).

\t (barra invertida y t): sirve para encontrar un carácter de tabulación horizontal (el que se inserta al pulsar la tecla Tab del teclado).

\v (barra invertida y v): sirve para encontrar un carácter de tabulación vertical (en ASCII tiene asignado el 11).

[\b] (corchete apertura, barra invertida, b y corchete de cierre): permite identificar un carácter de retroceso en un texto.

\d (barra invertida y d): se trata de uno de los metacaracteres más útiles y usados. Permite buscar cualquier dígito, es decir, es lo mismo que escribir [0-9] para usar un intervalo, tal y como vimos en el post anterior. Por ejemplo, al buscar \d euros en un editor compatible con regexp clásicas (por ejemplo, EditPad Lite), encontraríamos en un texto tanto 5 euros como 7 euros.

\D (barra invertida y D mayúscula): sirve para justamente lo contrario a lo anterior, es decir, para buscar todo lo que no sean dígitos. Se trata por tanto, del equivalente a [^0-9].

\w (barra invertida y w): otro de los metacaracteres más utilizados ya que permite localizar cualquier carácter alfanumérico (en mayúscula o minúscula) y el guión bajo. Por tanto, es igual al patrón [a-zA-Z0-9_]. Por ejemplo, con la búsqueda [Cc][Rr]\w encontraríamos tanto CR7 como crocs.

\W (barra invertida y W mayúscula): sirve para lo contrario a lo anterior, es decir, encontrar un carácter no alfanumérico ni un guión bajo; sería el equivalente a [^a-zA-Z0-9_]. Se puede utilizar para buscar caracteres de formato (párrafo, saltos, etc.) u otros como #.

\s (barra invertida y s): sirve para encontrar cualquier tipo de carácter de espacio en blanco. Es por tanto equivalente a [\f\n\r\t\v]. Por ejemplo, al buscar por \s en el texto Uno y dos, el texto que se identificaría serían los espacios en blanco (Unoydos).

\S (barra invertida y S mayúscula) lo contrario a lo anterior, es decir, lo mismo que [^\f\n\r\t\v]. Nos permite encontrar un carácter del tipo de todo lo que es «visible» al ojo humano en un texto.

\b (barra invertida y b): este metacaracter es muy útil porque sirve para marcar una posición de un carácter dentro de una palabra. Habitualmente se usa para buscar caracteres al principio. Por ejemplo: al buscar por \barm se encontrarían las palabras armadura y arma, pero no harmónica puesto que el patrón de búsqueda arm no está al principio de palabra en el último caso. Aunque se usa especialmente para marcar el inicio de una palabra, \b también sirve para marcar el final; por ejemplo, la búsqueda ato\b serviría para encontrar pazguato, pero no atornillar. Por último, si se combina el uso para inicio y final de palabra, lo que obtenemos es el equivalente a la búsqueda de palabra completa; por ejemplo, \bagua\b encontrará agua pero no aguantar. Por su uso, este es un metacaracter marcador de posición dentro de una palabra.

\B (barra invertida y B mayúscula): sirve para no encontrar un carácter en los límites de una palabra. Se usa, por ejemplo, para localizar guiones de separación en palabras en inglés (no hay espacios a los lados) con regexp como \B-\B, con las que se obtendrían resultados como taskrelated.

^ (acento circunflejo): fuera de un corchete, el acento circunflejo sirve para marcar el inicio de una cadena completa. Ojo, hemos dicho cadena, no palabra. En términos habituales, esto significaría comienzo de una frase en una nueva línea. Por ejemplo, ^\w nos serviría para localizar el primer carácter alfanumérico de una frase o cadena. En algunas implementaciones se suele ver \A en lugar de ^.

$ (símbolo del dólar): sirve para lo mismo que el metacaracter anterior, solo que en este caso se encuentra el final de una cadena. Por ejemplo, :$  nos permitiría encontrar todas las cadenas que terminen en dos puntos. En algunas implementaciones se suele ver \Z en lugar de $.

Como podemos intuir, la combinación de estos metacaracteres con los patrones de búsquedas tratados en el primer artículo de esta serie sobre expresiones regulares multiplica las prestaciones de las que disponemos. A modo de ejemplo práctico en el mundo de la traducción, podemos ver la combinación de caracteres literales y comodines (metacaracteres) en la creación de reglas de control de calidad o QA en la mayoría de las herramientas CAT del mercado. Habitualmente, las funciones de QA operan de la siguiente manera:

1) Se busca la aparición (o ausencia) de un patrón determinado en el texto de origen y

2) Se compara el resultado del primer paso para verificar la existencia (o no existencia) de dicho patrón en el texto de destino.

En concreto y para verlo con más claridad, vamos a definir una regla que busque los números con punto como separador de decimales en el texto de origen y que en el texto de origen NO tengan como separador de decimales una coma.

a) Expresión regular para el texto de origen: \d\.\d.

– Explicación: expresión formada por cualquier número (\d), punto (como punto es un metacaracter por sí mismo, lo escapamos con la barra invertida) y de nuevo cualquier número.

– Resultado: se encontraría, por ejemplo, 10.1, 512,684.58, 4.6.

b) Expresión regular para el texto de destino: [^\d,\d].

– Explicación: expresión formada por cualquier número (\d), coma y de nuevo cualquier número.

– Resultado: se encontraría, por ejemplo, 10,1, 512.684,58, 4,6.

Como se observa, en realidad lo que se hace es decirle al programa mediante una expresión regular lo siguiente “si en un segmento de origen encuentras un número, un punto y otro número y en el segmento de destino correspondiente hay un número separado de otro por algo que no sea una coma, genera un error de QA para que lo compruebe». En concreto, en este caso vemos como en el número 512.684,58 se habría producido un falso positivo (¡el tema de los falsos positivos daría para otro post!), puesto que aquí el punto separa las unidades de millar, no los decimales. En el resto de casos, no habría habido ningún problema.

QA reg exp en SDLX

Expresión regular para función de QA en SDLX

Esta última explicación y ejemplo es uno de los casos más habituales de uso de las expresiones regulares. No obstante, existen muchos más escenarios como, entre otros, el filtrado de cadenas en el editor de traducción, la extracción de cadenas en la ingeniería de traducción con patrones complejos, etc. La verdad es que una vez se dominan bien todos los operadores básicos, cada cual es capaz de idear aplicaciones de lo más variopintas en su trabajo y su día a día.

En este segundo artículo de la serie sobre regexp hemos tratado los metacaracteres como complementos indispensables para los operadores de regexp básicos a fin de buscar y encontrar patrones textuales más sofisticados. Pero, ¿no sirven todos estos metacaracteres vistos para localizar caracteres individuales? En el ejemplo [^\d,\d], ¿no se resaltaban con la búsqueda únicamente el número anterior (\d) y posterior al separador de decimales (,\d)? ¿Qué pasa si queremos buscar más números o caracteres y combinar en una búsqueda patrones más grandes en que se repitan caracteres, espacios en blanco, etc.?

Obviamente, todo eso se pensó al diseñar las expresiones regulares, así que nosotros lo veremos en el siguiente post de esta serie, donde trataremos la búsqueda y creación de repeticiones de caracteres y búsquedas, los cuantificadores, las subexpresiones y muchas más cosas con las que podremos aprovechar toda la potencia que nos brindan las regexp.

Mientras tanto, como en el caso anterior, a practicar con lo ya aprendido, ¿de acuerdo?

Nos leemos en más o menos un mes. Ah, y como siempre, perdonad que me enrolle tanto y termine por escribir post larguísimos. Un saludo a todos,

Álvaro

Recomendación musical: tras casi dos años de espera si no me equivoco, mis apreciados Stereophonics vuelven a la carga con nuevo material y sello discográfico propio. Aquí va el single titulado In A Moment.