Complemented character list (1)

Una de las cosas que me gusta de impartir clases es el poder aprender a través de éstas. No importa si es un tema que uno ya conozca o que uno considere agotado, siempre habrá oportunidad de conocer algo más o de poder resolver un nuevo misterio.

En un semestre pasado se presentó una de estas situaciones, cuando ejemplificaba la forma de representar expresiones regulares (ER) en el lenguaje AWK, que me llevó a ahondar más en algo que en un inicio parecía trivial.

Revisando la declaración de expresiones regulares que involucraban el uso de una clase de caracteres, ocurrió que una de ellas no funcionó como esperaba, en este caso:

/^[ABC]/

La documentación de AWK cita, sobre el uso del carácter circunflejo (^) dentro de lo que se conoce como una declaración de clase de caracteres, lista de caracteres, conjunto de caracteres o expresión de corchetes ([ ]) lo siguiente: “si éste es el primer carácter de la lista entonces es una indicación de que se buscará hacer un empate de cualquier carácter excepto aquellos que formen la lista.” En otras palabras, se trata de una ER que trabaja sobre el complemento de una lista de caracteres.

Así entonces la interpretación del ejemplo citado sería:

todos aquellos caracteres excepto A, B o C mayúsculas.

Por alguna razón esta interpretación me llevó a considerar que, al aplicarla sobre un flujo de entrada, me devolvería todos aquellos registros que no incluyeran las letras A, B o C mayúsculas. Error.

Supongamos que el contenido de un directorio es el siguiente:

$> ls

1.gif Archivo.pdf PDRM76565.jpg docto.doc
1post.txt B PRDM43453.JPG post.txt
345.pdf B17646.pdf a.txt reporteABC.xls
7657656hs.tff GAS.doc aBejas.gif test.txt

Uno podría pensar que el aplicar la ER sobre estos nombres debería excluir a todos aquellos cuyo nombre llevan las letras de la clase declarada. Sin embargo

> ls * | awk '/[^ABC]/'

1.gif
1post.txt
345.pdf
7657656hs.tff
Archivo.pdf
B17646.pdfGAS.doc
PDRM76565.jpg
PRDM43453.JPG
a.txt
aBejas.gif
docto.doc
post.txt
reporteABC.xls
test.txt

podemos ver que hay archivos con dichas letras. ¿Qué pasó? Pues bien, la exclusión de las letras indicadas en la clase de caracteres precisamente implica el empate contra el complemento de dicho conjunto aunque la semántica nos lleve a pensar que es lo contrario, es decir, que todo aquello que tenga los caracteres de la clase sea excluido.

Por ejemplo, si bien podemos esperar que archivos con nombres de una sola letra (como el que simplemente se llama B) deben ser excluidos, podemos también equivocadamente pensar que archivos cuyo nombre llevan este caracterer, como aBejas.gif, también deberían excluirse. Pero, como vemos, no ocurre así. ¿La razón? El simple hecho de que el nombre del archivo incluya otros caracteres que precisamente no son parte de la lista de caracteres a evitar confirma la regla señalada, y así son presentados.

Para entender mejor el asunto consideremos el complemento de la ER y así sus resultados. En otras palabras, veamos qué pasa si lo que deseamos mostrar es todos aquellos nombres del flujo de entrada en el que aparezcan letras A, B o C.

$> ls * | awk '/[ABC]/' | more

Archivo.pdf
BB17646.pdf
GAS.doc
aBejas.gif
reporteABC.xls

Podemos ver que efectivamente se cumple con la interpretación de la ER, cosa que no ocurre con complemento la lista de caracteres. Esto sólo nos indica que si bien se está colocando el complemento de la ER original no ocurre así con el funcionamiento que AWK muestra en su ejecución.

Veamos el problema desde otra perspectiva. Consideremos a la última ER usada pero explícitamente declarando el registro sobre el que trabaja, esto es

/$0 ~ [ABC]/

que al ser aplicada produce el mismo resultado ya mostrado

$> ls * | awk '$0 ~ /[ABC]/' | more

Archivo.pdf
BB17646.pdf
GAS.doc
aBejas.gif
reporteABC.xls

¿Cuál es el complemento de este script? Aquel que no muestre estas líneas, aquel que muestre aquellos registros que no empatan con la ER declarada, y que es el que se obtiene negando la operación de empate. Así

$> ls * | awk '$0 !~ /[ABC]/' | more

1.gif
1post.txt
345.pdf
7657656hs.tff
PDRM76565.jpg
PRDM43453.JPGa
a.txt
docto.doc
post.txt
test.txt

esto precisamente nos demuestra que el declarar el complemento de un conjunto de caracteres con el que trabajará la ER no implica obtener el resultado complementario de la operación de dicha ER.

Responder

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