lunes, 20 de junio de 2016

Clases de caracteres POSIX

Los rangos tradicionales de caracteres son una forma fácilmente compresible y efectiva de manejar el problema de especificar colecciones de caracteres rápidamente. Desafortunadamente, no siempre funcionan. Aunque no hemos encontrado problemas usando grep hasta ahora, podríamos tener problemas con otros programas.

Volviendo al capítulo 4, vimos cómo los comodines se usan para realizar expansiones en los nombres de las rutas. En dicho tema, dijimos que los rangos de caracteres podían usarse de forma casi idéntica a la forma en que se usan en expresiones regulares, pero aquí está el problema:

[me@linuxbox ~]$ ls /usr/sbin/[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*
/usr/sbin/MAKEFLOPPIES
/usr/sbin/NetworkManagerDispatcher
/usr/sbin/NetworkManager

(Dependiendo de la distribución Linux, obtendremos una lista diferente de archivos, posiblemente una lista vacía. Este ejemplo es de Ubuntu). Este comando produce el resultado esperado - una lista de los archivos cuyos nombres comienzan con una letra mayúscula, pero:

[me@linuxbox ~]$ ls /usr/sbin/[A-Z]*
/usr/sbin/biosdecode
/usr/sbin/chat
/usr/sbin/chgpasswd
/usr/sbin/chpasswd
/usr/sbin/chroot
/usr/sbin/cleanup-info
/usr/sbin/complain
/usr/sbin/console-kit-daemon

con este comando obtenemos un resultado completamente diferente (sólo se muestra una lista parcial de resultados). ¿Por qué? Es una larga historia, pero aquí tienes un resumen:

En la época en que Unix fue desarrollado por primera vez, sólo entendía caracteres ASCII, y esta característica refleja este hecho. En ASCII, los primeros 32 caracteres (los números 0 a 31) son códigos de control (cosas como tabuladores, retrocesos y retornos de carro). Los siguientes 32 (32 a 63) contienen caracteres imprimibles, incluyendo la mayoría de los signos de puntuación y los números del cero al nueve. Los siguientes 32 (64 a 95) contienen las letras mayúsculas y algunos signos de puntuación más. Los últimos 31 (números del 96 al 127) contienen las letras minúsculas y todavía más signos de puntuación. Basándose en esta disposición, los sistemas que usan ASCII utilizan una secuencia de ordenado (collation order) que tiene esta pinta:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

Esto difiere del orden correcto del diccionario, que es así:

aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ

Cuando la popularidad de Unix se expandió fuera de los Estados Unidos, creció la necesidad de soportar caracteres que no existen en el inglés de EE.UU. La tabla ASCII se incrementó para usar ochos bits completos, añadiendo los números de caracteres 128-255, que albergan muchos más idiomas. Para soportar esta capacidad, los estándares POSIX introdujeron un concepto llamado un locale o configuración regional, que puede ajustarse para seleccionar el conjunto de caracteres necesarios para una localización particular. Podemos ver la configuración de idioma de nuestro sistema usando este comando:

[me@linuxbox ~]$ echo $LANG
en_US.UTF-8

Con esta configuración, las aplicaciones compatibles con POSIX usarán la secuencia de ordenado del diccionario en lugar del orden ASCII. Esto explica el comportamiento de los comandos anteriores. Un rango de caracteres de [A-Z] cuando es interpretado en orden del diccionario incluye todos los caracteres alfabéticos excepto la "a" minúscula, de ahí nuestros resultados.

Para evitar este problema, el estándar POSIX incluye un número de clases de caracteres que proporcionan rangos útiles de caracteres. Están descritas en la siguiente tabla:

Tabla 19-2: Clases de caracteres POSIX
Clases de Caracteres Descripción
[:alnum:] Los caracteres alfanuméricos. En ASCII, equivalente a:
[A-Za-z0-9]
[:word:] Los mismo que [:alnum:], con el añadido del carácter subrayado (_).
[:alpha:] Los caracteres alfabéticos. En ASCII, equivalente a:
[A-Za-z]
[:blank:] Incluye los caracteres del espacio y tabulador.
[:cntrl:] Los caracteres de control ASCII. Incluyen los caracteres ASCII del 0 al 31 y el 127.
[:digit:] Los números del cero al nueve.
[:graph:] Los caracteres visibles. En ASCII, incluye los caracteres del 33 al 126.
[:lower:] Las letras minúsculas.
[:punct:] Los símbolos de puntuación. En ASCII, equivalente a:
[-!"#$%&'()*+,./:;<=>?@[\\\]_`{|}~]
[:print:] Los caracteres imprimibles. Los caracteres de [:graph:] más el carácter espacio.
[:space:] Los caracteres de espacio en blanco, incluyendo el espacio, el tabulador, el retorno de carro, nueva linea, tabulador vertical, y salto de página. En ASCII equivalente :
[ \t\r\n\v\f]
[:upper:] Los caracteres en mayúsculas.
[:xdigit:] Los caracteres usados para expresar números hexadecimales. En ASCII, equivalente a:
[0-9A-Fa-f]

Incluso con las clases de caracteres, sigue sin haber una forma conveniente de expresar rangos parciales, como [A-M].

Usando las clases de caracteres, podemos repetir nuestro listado de directorios y ver un resultado mejorado:

[me@linuxbox ~]$ ls /usr/sbin/[[:upper:]]*
/usr/sbin/MAKEFLOPPIES
/usr/sbin/NetworkManagerDispatcher
/usr/sbin/NetworkManager

Recuerda, sin embargo, que esto no es un ejemplo de expresión regular, es por el contrario el resultado de una expansión de ruta que realiza el shell. Lo vemos porque las clases de caracteres POSIX pueden usarse en ambos casos.

No hay comentarios:

Publicar un comentario