domingo, 27 de mayo de 2012

Un correo esotérico, parte 1

Habiendo mencionado un poco sobre la lectura/escritura de archivos de texto, les puedo proponer un simpático problema de programación que pueden resolver utilizando los conocimientos de Python que se han dado hasta ahora en este blog.

Un amigo mío me mando un día el siguiente correo:

:
:
:

El correo original consta de 22 páginas de ... ¡ceros y unos!  Pueden descargar el archivo de texto con la secuencia de dígitos binarios en este enlace.  La misión de ustedes será hacer un script en Python para "decifrar" esta secuencia de ceros y unos.  Quiero que observen lo siguiente:
  • Los ceros y unos están agrupados en grupos de 8 bits (cifras binarias).
  • Cada grupo de 8 bits seguramente representa algo... ¿Una letra o un caracter?
  • ¿Cómo representámos caracteres y letras en un computador? ¿Cuál sistema de codificación se usa más frecuentemente?
Traten de decifrar el mensaje antes de que yo publique el script para decifrarlo como siguiente entrada de este blog.




Archivos de texto

En esta entrada veremos como trabajar con archivos simples en python.  El tipo más simple de archivos es sin duda el archivo de texto.  Un archivo de texto es una sucesión de caracteres organizada en secuencias de líneas que reside en "algún lugar" de un dispositivo de almacenamiento secundario (disco duro, pen drive, cd rom, etc.) y al cual podemos acceder mediante su ruta.  La ruta es el camino en la jerarquía de directorios que indica de manera univoca en que parte de cual dispositivo de almacenamiento secundario reside el archivo. 


Un poco sobre las rutas de archivos


En linux, la raiz de toda ruta es "/". A partir de allí se indican los directorios y subdirectorios sucesivos separando los mismos mediante la barra diagonal "/". Por ejemplo,

/home/jlaurentum/Documentos/nota.txt

sería la ruta completa de un archivo llamado "nota.txt" que reside en el disco duro de mi computadora.  Notese que el elemento final de la ruta es el nombre del archivo en sí y que los archivos tienen terminaciones o sufijos que se indican despues del punto "." en su nombre.  Así, algunas terminaciones comunes son ".tex", ".odt", ".bin" que van asociadas a los archivos de LaTeX, Libre Office Writer y programas ejecutables en Linbux respectivamente.  Un sufijo de nombre de archivo particularmente importante para nosotros es ".py", el cual denota archivos de código fuente en Python, los cuales por cierto son archivos de texto tambien.

En Güindou$, el caracter separador de directorio en las rutas es la barra diagonal invertida "\".  Para especificar la raiz, hay que identificar el dispositivo de almacenamiento o la partición del disco duro mediante una letra seguida de ":".  Así por ejemplo, en la computadora de mis esposa (que es Guindou$-dependiente), tengo un archivo cuya ruta es:

C:\Mis documentos\jlaurentum\nota.txt

Yo evito usar espacios y caracteres raros en los nombres de mis directorios o de mis archivos.  Para separar las palabras de un nombre, utilizo el caracter de piso "_" o el guión "-" en vez del espacio " ".  Bueno, con esto estamos listos para ver cómo se trabajan con archivos en python.

El protocolo de trabajo con archivos de texto: abrir, leer/escribir y cerrar


Desde el punto de vista de programación en Python, podemos ver los archivos como objetos.  Cuando creamos una instancia de tipo archivo (mediante la sentencia open), indicamos la ruta del archivo y el modo de acceso al archivo, siendo este:

  • de escritura, indicado por "w" en el argumento modo de open.  Sólo será posible escribir al archivo.  Si no existe el archivo en la ruta, al abrirlo se crea.
  • de lectura, indicado por "r" en el argumento modo de open.  Sólo será posible leer el arhivo.
  • para anexar, indicado por "a" en el argumento modo de open.  Se podrá escribir sólo al final del archivo, sin modificar el contenido existente.
  • de lectura/escritura, indicado por "r+" en el argumento modo de open.  Se podrá leer y escribir al archivo.
Existen otros argumentos para modo, pero con estos basta.  Si abrimos un archivo para lectura pero este no existe en la ruta proporcionada, se genera un error.  Por ejemplo, vamos a suponer que me equivoco al escribir el nombre de nota.txt y escribo nata.txt (el cual no existe). Entonces, al abrir el archivo en Python, tendría un error:


>>> mi_archivo = open("/home/jlaurentum/Documentos/nata.txt","r")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No existe el archivo o el directorio: '/home/jlaurentum/Documentos/nata.txt'
>>>


En otro post veremos como acceder a algunas funciones del sistema operativo verificar si un archivo existe, obtener un listado de archivos en un directorio, etc.  Supóngase pues, que "nota.txt" es un archivo de texto que contiene lo siguiente (puedes copiar y pegar este archivo y guardarlo en tu computadora para hacer las pruebas):


Este es un archivo de prueba.
Esta es la segunda línea.
Y esta es la tercera línea.


Intentamos una vez más abrir el archivo (habiendolo guardado previamente en la ruta que indicamos):


>>> mi_archivo = open("/home/jlaurentum/Documentos/nota.txt","r")
>>>


¡Éxito!  Notese que el método open, cuando es exitoso, crea una instancia nueva de la clase file (archivo). Así, mi_archivo es un objeto tipo file:

>>> type(mi_archivo)
<type 'file'>
>>>



Una vez que abrimos un archivo para lectura, estamos listos para acceder a él.  Vamos a visualizar el contenido de "nota.txt" con el siguiente script:


>>> for linea in mi_archivo:
...     print linea
...
Este es un archivo de prueba.

Esta es la segunda línea.

Y esta es la tercera línea.

>>>


Observen la sentencia for- es bastante elocuente para entender que python "vé" los archivos de texto como una secuencia de líneas.  Sin darnos cuenta, ya hemos leido todas estas líneas e inclusive las hemos imprimido. Pero ... algo anda mal. ¿Porqué hay un espacio adicional entre las líneas?  Resulta que cada línea en el archivo original termina en "\n", que es el caracter invisible que indica una nueva línea.  Cuando se imprime el "\n" al final de cada línea, se imprime un salto de línea adicional al salto de línea que imprime la sentencia print.  Por eso tenemos el interlineado de arriba.  Para corregir esto, lo que tenemos que hacer es eliminar el caracter final de cada línea cuando este es un "\n".  Sin embargo, tenemos que volver a abrir el archivo nuevamente porque en el último for lo leimos todo hasta el final:


>>> mi_archivo=open("/home/jlaurentum/Documentos/nota.txt","r")
>>> for linea in mi_archivo:
...     if linea[-1]=="\n":
...             linea=linea[:-1]
...     print linea
...
Este es un archivo de prueba.
Esta es la segunda línea.
Y esta es la tercera línea.
>>>


¡Qué éxito! Pero se nos ha olvidado algo muy importante: cerrar el archivo tras haber trabajado con él:


>>> mi_archivo.close()
>>>


No se puede repetir lo suficiente lo importante que es cerrar los archivos al final.  Si no lo hacemos, los cambios que hacemos al archivo en modo escritura se pueden perder o peor aún, el archivo puede corromperse y quedar inservible.

Ahora vamos a probar la escritura de archivos.  Normalmente, cuando yo quiero procesar el contenido de un archivo, lo que hago es abrir una copia en modo lectura y crear otro archivo en modo escritura al cual voy a escribir el contenido del primer archivo procesado.  Por ejemplo, supóngase que quiero recorrer todo el archivo "nota.txt" para cambiar la palabra "la" por "su":


>>> mi_archivo.close()
>>> mi_archivo=open("/home/jlaurentum/Documentos/nota.txt","r")
>>> otro_archivo=open("/home/jlaurentum/Documentos/nota2.txt","w")
>>> for linea in mi_archivo:
...     linea=linea.replace("la","su")
...     otro_archivo.write(linea)
...
>>> otro_archivo.close()
>>> mi_archivo.close()
>>>



Entonces, buscamos el archivo "nota2.txt" y lo abrimos con el editor de texto, verificando su contenido:


Este es un archivo de prueba.
Esta es su segunda línea.
Y esta es su tercera línea.



Para este ejemplo, tuvimos suerte.  El método replace sustituye todas las ocurrencias de su primer argumento por la cadena suministrada en su segundo argumento.  Si hubiesemos tenido una palabra como "reemplazarla", se hubiese cambiado a "reemplazarsu", lo cual seguramente no hubiesemos querido.  En otra entrada de este blog hablaremos de expresiones regulares, que nos permitirán hacer un procesamiento más avanzado con data de texto.


Exiten otras formas de leer un archivo, por ejemplo, podemos leer el archivo caracter por caracter.  El siguiente script cuenta el número de caracteres de nuestro archivo de ejemplo:


>>> mi_archivo=open("/home/jlaurentum/Documentos/nota.txt","r")
>>> contador=0
>>> caracter=mi_archivo.read(1)
>>> while caracter!="":
...     contador+=1
...     caracter=mi_archivo.read(1)
...
>>> print contador
87
>>> mi_archivo.close()
>>>



Este archivo contiene 87 caracteres, es decir, su tamaño es de 87 bytes.  Observen que esto concuerda con lo que nos reporta la consulta de las propiedades de ese archivo.  Tambien podemos leer el archivo de un sólo trancazo en memoria, como una lista de cadenas:


>>> mi_archivo=open("/home/jlaurentum/Documentos/nota.txt","r")
>>> lineas=mi_archivo.readlines()
>>> print lineas
['Este es un archivo de prueba. \n', 'Esta es la segunda l\xc3\xadnea.\n', 'Y esta es la tercera l\xc3\xadnea.\n']
>>> mi_archivo.close()
>>>



Los elementos raros en esta lista de cadenas se corresponden a caracteres especiales, como la "í" con acento en "línea", cuya codificación  utf-8, en 2 bytes, es c3ad.

Finalmente, hasta las páginas web se pueden leer como archivos de texto.  Por ejemplo, el siguiente script abre la página de la primera entrada de este blog:


from urllib import *
pagina=urlopen("http://mont-epython.blogspot.com/2011/06/como-primera-entrada-de-este-blog.html")
for linea in pagina:
    print linea[:-1]
pagina.close()


No se indicó la salida del interprete python en rojo porque este script imprime muchas líneas.  Observen que el tratamiento de una página web es virtualmente idéntico al de un archivo de texto: lo abrimos, lo leemos y lo cerramos.  La ruta del archivo es simplemente la dirección URL de la página, pero al abrir esta página y leerla, no vemos lo que veriamos en el navegador, vemos otra cosa.  ¿Qué exactamente? ¡Corran el script y averigüenlo!






Referencias


miércoles, 23 de mayo de 2012

Libros con listados de video juegos en BASIC

Cuando yo era chamo (vaya que este blog se pone bastante nostálgico a veces), las revistas y libros sobre computación muchas veces incluian listados de programas (en BASIC) que uno podía meter en su computadora, ejecutarlos y luego modificarlos a su antojo.  Cuando estos programas eran de video-juegos, yo no los pelaba...

A continuación les dejo los enlaces de algunos de estos libros viejos que encontré digitalizados en la web.  Los programas son en lenguaje BASIC (que era el equivalente de Python en aquellos días).  Lamentablemente, la mayoría de los libros que conseguí estan en Inglés, pero incluyen una explicación detallada de los videojuegos (con código BASIC incluido).  Ustedes pueden tomar alguna idea de estos libros como punto de partida para sus proyectos de videojuegos.


Computer Battlegames

Estos son juegos de batallas.  La mayoria de los juegos en este libro son de texto y muy sencillos, pero creo que al final hay uno o dos juegos que son "de acción" y con gráficos, aunque muy limitados por las capacidades de los computadores en aquella epoca.  Quizás pudiesen tomar la trama de estos como punto de partida para hacerlos más complejos.                                                
Basic Fun with Adventure Games

Aqui se desarrolla un solo juego de aventura de texto, donde la trama es que el jugador es un agente de la CIA (si, del imperio mismo) que esta tratando de buscar evidencia para incriminar al embajador ruso.
Island of Secrets

Otro juego de aventura de texto.
Programa tus propias Aventuras en tu computadora

Este libro es excelente. Se desarrolla el listado para un juego de aventura de texto en una casa embrujada, pero también explica como funcionan las distintas partes de un juego de aventura de texto y cómo diseñarlos.
Creating Simulation Games on Your Computer

Este libro incluye varios programas de juegos de simulación.

¡Que se diviertan!

lunes, 21 de mayo de 2012

Efectos de consola, parte 3

Una escena maritima

En nuestro afan por sacarle el jugo a la cónsola (dejaremos el tema de las interfaces gráficas para luego), en esta entrada ilustraremos cómo crear animaciones simples y agregar color al texto en la cónsola.  Por ejemplo, la escena marítima que ven a continuación fue hecha exclusivamente usando la cónsola de texto:


Por cierto, el script que realiza esta animación fué realizado por Leober Urbano y Daniel Vasquez, ambos estudiantes de mi curso de Python en la UNEFA este semestre (2012-1).  Pero antes de darles el código (con el permiso de ellos), quiero presentarles las secuencias de escape ANSI.

Secuencias de escape ANSI - Un poco de historia

Mucho antes de que existieran los entornos de interfáz gráfica (con ventanitas, ratones, iconos y todas esas cosas a las cuales ustedes se han (mal)acostumbrado), de hecho, antes de que existieran las primeras computadoras personales, la típica configuración computacional era una computadora mainframe con un sistema operativo que permitía el time-sharing y con el cual los usuarios en una sala de computación interactuaban mediante unos terminales de texto, como por ejemplo el famoso VT-100 que ven a continuación (pueden buscar el artículo en la Wikipedia):

Una cónsola VT-100.
Nótese el uso de la palabra cónsola,
aqui bajo su acepción original,
 que se refería a todo el dispositivo
de entrada-salida (pantalla y teclado).

Estos terminales nos parecerian increiblemente limitados hoy en día.  La información era visualizada como caracteres ASCII  y algo llamado "secuencias de escape ANSI" que permitía visualizar estos caracteres con otros atributos (por ejemplo, resaltados, subrayados, parpadeando, etc.).  Además, las secuencias de escape ANSI permitían (y permiten todavía como vamos a ver) controlar en cuál parte de la pantalla se visualizaba la información. Las secuencias de escape ANSI pronto se conviertieron en un estándar para todas las consolas, igual que los caracteres ASCII.

Aunque ustedes no me crean, yo llegué a usar estas perolas cuando estudiaba computación en la Universidad Central de Venezuela (a principio de los 90's).  Las consolas en cuestión estaban conectadas a una Burroughs B6700, a la cual nosotros en la Escuela de Computación nos referiamos, no tan cariñosamente, como la "Burro".

Secuencias de escape ANSI - ¿que son?

Todo comando para lograr los "efectos especiales" como los que se ven en la animación de arriba comienza por imprimir (mediante una sentencia print en Python) un iniciador de secuencia de control, o CSI por sus siglas en inglés.  Existen CSI's de un caractér, como por ejemplo los que emitimos para dar un salto de línea, una tabulación horizontal o vertical, mandar un beep al terminal.  Estos CSI's de un caracter fueron expuestos en la primera parte de esta serie de entradas sobre efectos de la cónsola.  Ahora, los que nos interesan son los comandos que podemos emitir con el CSI de dos caracteres: ESC+[ (un caracter de escape, código ASCII 27 en decimal, más el caracter de corchete cuadrado izquierdo, código ASCII 91 en decimal).  Por ser el primer caracter el ESCape, las secuencias de control que comienzan con este CSI se conocen como secuencias de escape ANSI.  Despues del CSI, los otros caracteres que se imprimen a continuación indican más información sobre la secuencia de control.  A continuación una lista no exhaustiva:

Comandos ANSI para posicionamiento de cursor, desplazamiento o borrado


Comando
(Secuencia de caracteres)
Descripción
CSI n A Mueve el cursor n caracteres (por defecto n=1) hacia arriba.
CSI n B Mueve el cursor n caracteres (por defecto n=1) hacia abajo.
CSI n C Mueve el cursor n caracteres (por defecto n=1) adelante (hacia la derecha).
CSI n D Mueve el cursor n caracteres (por defecto n=1) atrás (hacia la izquierda).
CSI n E Mueve el cursor al principio de la línea y n líneas (por defecto n=1) hacia abajo.
CSI n F Mueve el cursor al principio de la línea y n líneas (por defecto n=1) hacia arriba.
CSI n G Mueve el cursor a la columna n.
CSI n;m H Mueve el cursor a la posición indicada por la fila n y la columna m (por defecto n y m son iguales a 1). La posición (1,1) es la esquina superior izquierda de la ventana.
CSI n J Borra parte de la pantalla. Si n=0 (valor por defecto), limpia la pantalla desde la posición del cursor hasta el final. Si n=1, limpia la pantalla desde el cursor hasta el principio de la pantalla. Si n=2, limpia toda la pantalla.
CSI n K Borra parte de la línea. Si n=0 (valor por defecto), limpia desde la posición del cursor hasta el final de la línea. Si n=1, limpia desde el cursor hasta el principio de la línea. Si n=2, limpia toda la línea. La posición del cursor no varía.
CSI n S Desplaza toda la pantalla n líneas hacia arriba (por defecto n=1) insertando las n líneas desde abajo.
CSI n T Desplaza toda la pantalla n líneas hacia abajo (por defecto n=1) insertando las n líneas desde arriba.
CSI 6 n Captura la posición actual del cursor como si el usuario la hubiese ingresado por teclado. Se devuelve la siguiente secuencia de caracteres: ESC[n;mR , donde n y m son los números de fila y columna respectivamente. Notese que en esta secuencia de escape (CSI 6 n), la n representa una n minúscula y no un número pasado como parámetro.
CSI s Guarda la posición del cursor.
CSI u Restaura la posición del cursor a la posición guardada por CSI s.
CSI ?25l Esconde el cursor.
CSI ?25h Vuelve a visualizar el cursor.

En las secuencias de escape antecedentes, las letras n y m en cursiva representan parametros numericos que se pasan al interprete ANSI.  Así por ejemplo, la secuencia ESC[2;40H ubicaría la posición del cursor en la fila 2, columna 40.

Existe una secuencia de escape especial para modificar los atributos de los caracteres enviados a la pantalla.  Es la secuencia de escape especial de rendición gráfica (SGR por sus siglas en inglés), que se corresponde a

CSI n;[k] m

En lo anterior, n y k son parámetros númericos, k es un parámetro opcional.  Nótese que la secuencia de escape termina en m minuscula.  A continuación una descripción de los atributos modificables mediante el o los parámetros n y k:

Comandos de rendición gráfica


Parámetro Descripción
0 Restaura todos los atributos de rendición grafica a los valores por defecto (reset).
1 Coloca texto en negrillas o alta intensidad.
4 Coloca texto subrayado.
5 Coloca texto en parpadeo lento.
6 Coloca texto en parpadeo rápido.
7 Invierte (intercambia) los colores de fondo y de primer plano.
21 Desactiva las letras en negrilla y visualiza el texto en intensidad normal.
24 Desactiva el subrayado.
25 Desactiva el parpadeo.
30-37 Fija el color del texto (primer plano) en baja intensidad. El segundo dígito despues del 3 indica el color. Ver tabla anexa abajo.
40-47 Fija el color de fondo en baja intensidad.El segundo dígito despues del 4 indica el color.Ver tabla anexa abajo.
90-97 Fija el color del texto (primer plano) en baja intensidad.El segundo dígito despues del 9 indica el color. Ver tabla anexa abajo.
100-107 Fija el color de fondo en baja intensidad.El segundo dígito despues del 10 indica el color. Ver tabla anexa abajo.

Tabla de colores


Intensidad 0 1 2 3 4 5 6 7
Baja Negro Rojo Verde Amarillo Azul Magenta Cyan Gris claro
Alta Gris oscuro Rojo Verde Amarillo Azul Magenta Cyan Blanco

Haciendo uso  ingenioso de estas secuencias de escape y de algunos caracteres especiales unicode, Leober y Daniel hicieron su script para realizar una pequeña animación de un barco navegando:

import time
velas1= " "*5+u"\u2571"+u"\u23AA"+" "+u"\u23AA"+u"\u2572"
velas2= " "*4+u"\u2571"+" "+u"\u23AA"+" "+u"\u23AA"+" "+u"\u2572"
velas3= " "*3+u"\u2571"+"__"+u"\u23AA"+" "+u"\u23AA"+"__"+u"\u2572"
mastiles= " "*6+u"\u23AA"+" "+u"\u23AA"
timonel= " "*2+u"\u2599"+u"\u2588"*10+u"\u259f"
print "\n"*5
print "\033[11;0H"+"\033[0;34;44m"+u"\u2588"*80+"\033[0m"
for i in range(20):
 v=i+1
 print "\033[6;%dH"%v+velas1
 print "\033[7;%dH"%v+velas2
 print "\033[8;%dH"%v+velas3
 print "\033[9;%dH"%v+mastiles
 print "\033[10;%dH"%v+timonel
 time.sleep(0.5)
while i>0:
 v=i+1
 print "\033[6;%dH"%v+velas1+"\033[0K"
 print "\033[7;%dH"%v+velas2+"\033[0K"
 print "\033[8;%dH"%v+velas3+"\033[0K"
 print "\033[9;%dH"%v+mastiles+"\033[0K"
 print "\033[10;%dH"%v+timonel+"\033[0K"
 i=i-1
 time.sleep(0.5)

Referencias

  1. Wikipedia (2012). "ANSI escape code".  Artículo de Wikipedia disponible en: http://en.wikipedia.org/wiki/ANSI_escape_code. Nota: existe una versión en castellano de este artículo pero no es tan completa como la versión citada.
  2. Wikipedia (2012). "VT100". Artículo de Wikipedia disponible en: http://es.wikipedia.org/wiki/VT-100.
  3. s/a (2001). "Escuela de Computación|UCV|historia". Página web disponible en: http://www.ciens.ucv.ve/escueladecomputacion/inicio/historia
  4. s/a (2008). "Print in terminal using colors with python?". Pregunta en foro disponible en: http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python.

miércoles, 16 de mayo de 2012

Proyectos de Video-juegos semestre 2012-1

Hola a todos:

Tal como conversamos en clase, publico esta entrada en el blog para que me informen por vía de comentarios a esta entrada cuales son los grupos de trabajo y cual es la propuesta de video-juego de cada equipo.  Quiero que revisen con atención las entradas anteriores correspondientes al proyecto de video-juegos para el curso del semestre 2011-1, cuando dicté esta materia en la UNEFA.  Especificamente, quiero que consideren los siguientes puntos:

  1. Los mecanismos de co-evaluación diseñados por los estudiantes de aquél curso, los cuales se plasmaron en forma de una hoja de calculo con los criterios de evaluación y la ponderación de cada item.  Podemos comentar sobre la evaluación debajo de esta entrada.
  2. La dinámica de participación, las preguntas y las respuestas, los problemas con los que se topó cada equipo en el desarrollo de su video-juego y las soluciones a esos problemas.  Recuerden algo: ningún proyecto de programación de cierta envergadura sale bien la primera vez.  Siempre surgen errores, bugs, comportamientos inesperados, etc. Eso es algo normal en la dinámica del desarrollo de este tipo de proyectos, de modo tal que no se preocupen si su proyecto no está 100% acabado para la fecha de entrega.  La idea de debatir sobre estos trabajos en el blog es que todos podamos colaborar con los mismos.
  3. La mayoría de los equipos en el 2011-1 crearon blogs o páginas para servir de vitrina de sus respectivos video-juegos.  Un équipo en particular, el équipo del juego MundoLibo, habilito una cuenta en sourceforge para hospedar su trabajo.  Por si no lo saben, sourceforge es un servicio de hospedaje para desarrollo de aplicaciones en el cual los usuarios pueden comunicarse con los programadores para solventar dudas o bugs y descargar los binarios o programas de instalación de la aplicación.  Para los programadores/desarrolladores, sourceforge brinda muchas herramientas interesantes: control de versiones, herramientas para el desarrollo colaborativo, etc.  Consideren trabajar con sourceforge u otra herramienta similar (GitHub?).

sábado, 5 de mayo de 2012

Efectos de consola, parte 2

Sistemas de codificación de caracteres - Unicode


En la parte 1 de esta serie de posts vimos cómo imprimir algunos caracteres especiales que normalmente no podríamos indicar encerrandolos entre comillas. Para indicar estos caracteres, utilizabamos lo que se llaman secuencias de escape y en particular, había una para imprimir cualquier caracter ASCII- \xhh, en donde hh son los dos dígitos hexadecimales que conforman el còdigo ASCII del caracter.

El código ASCII es un estándar para la representación de símbolos y caracteres alfanuméricos. Cualquiera de los símbolos de uso común se podía representar como un byte (un octeto de bits) y consecuentemente, la tabla de caracteres ASCII comprendía hasta 256 símbolos. Entre estos, los primeros 128 símbolos eran comúnes a todos los sistemas de computadoras y comprendian el conjunto de símbolos de puntuación, el espacio, las 26 letras mayúsculas y minúsculas (excluyendo la eñe, la c con cedilla y otros caractéres regionales) y los 10 dígitos numéricos, o sea, los símbolos que comúnmente figuran en cualquier teclado.

Pronto se vió la necesidad de extender este conjunto de símbolos para poder incluir símbolos y letras de otras lenguas no europeas que usaban alfabetos distintos al romano. Ya de por sí el ASCII (por lo menos el conjunto de los primeros 128 símbolos verdaderamente estándar) era insuficiente para representar caracteres particulares de algunas lenguas europeas (como la ñ o las vocales con acentos en español, las vocales con dieresis y la ß alemana, etc.). Con esto en mente, se creo el estandar unicode a finales de la década de los 80.

Los códigos unicode son de longitud variable y las tablas de caracteres unicode se pueden consultar en http://www.unicode.org/charts/. A continuación un resúmen de los bloques de caracteres que me parecieron más interesantes:

Bloque Unicode Descripción
0000–007F Caracteres de control y Latin básico (este bloque es igual al primer bloque de los 128 caracteres ASCII)
2300–23FF Caracteres técnicos miscelaneos: símbolos de ingeniería, computación, químicos, diagramas eléctricos, etc.
2500–257F Caracteres para dibujo de cajas
2580–259F Bloques y cuadrantes.
2600-26FF Símbolos miscelaneos y de juegos: meteorología, astrología, signos viales, piezas de ajedrez, dados, símbolos religiosos y políticos, etc.
2700–27BF Dingbats - más símbolos miscelaneos.
2B00–2BFF Figuras geométricas y flechas


Existen dos sistemas de mapeo de caracteres unicode: el UTF (Unicode Transformation Format) y el UCS (Universal Character Set). Entre los sistemas UTF, los encodings (sistemas de codificación) más usados son el UTF-8, el UTF-16 y el UTF-32. Básicamente, el encoding UTF-8 es un encoding de 8 bits en los cuales cada caracter se representa como una secuencia de longitud variable de bytes (de 1 a 4 bytes). El UTF-8 permite una máxima compatibilidad con el sistema de codificación ASCII, pues los primeros 256 caracteres (codificación de 1 byte de longitud) son los caracteres ASCII. Los sistemas UTF-16 y UTF-32 son para máquinas con arquitecturas de 16 o 32 bits, lo cual no quiere decir que en estas máquinas no se pueda usar la codificación UTF-8.

Métodos de entrada de caracteres Unicode y cómo trabajar con Unicode en Python

En Linux, podemos ingresar caracteres Unicode desde la consola o editor de textos (o inclusive desde este navegador) apretando las teclas CTRL ( ⌃⃣ ) y SHIFT ( ⇧⃣ ) juntas.  Manteniendo estas teclas apretadas, tecleamos la letra "U"  seguida de los cuatro dígitos hexadecimales correspondientes al código Unicode del caracter que queremos.  Así por ejemplo:


Secuencia de Teclas Aparece el símbolo
⌃⃣ + ⇧⃣ + U⃣ + 2⃣ + 3⃣ + 1⃣ + A⃣ de un reloj: ⌚
⌃⃣ + ⇧⃣ + U⃣ + 2⃣ + 5⃣ + 0⃣ + C⃣ esquina de una caja: ┌
⌃⃣ + ⇧⃣ + U⃣ + 2⃣ + 6⃣ + 1⃣ + 5⃣ taza de té caliente: ☕
⌃⃣ + ⇧⃣ + U⃣ + 2⃣ + 6⃣ + 3⃣ + A⃣ soy feliz tomando té: ☺

Para trabajar con expresiones en Python que contengan caracteres unicode en literales de cadena, tenemos que agregar la letra u antes de las comillas del literal de la cadena.  Dentro de las comillas, colocamos la secuencia de escape \u (Ver Efectos de consola, parte 1) seguida de los cuatro digitos hexadecimales del caracter.  Al imprimir estas cadenas, se verán los caracteres unicode indicados por las secuencias de escape.  De esta forma, uno de mis estudiantes del curso de Python que dicto en la UNEFA creo un pequeño script en Python que dibuja una embarcación:

b=u"\u005C"
a=u"\u002F"
c=u"\u005F"
d=" "
e=u"\u25a0"
f=u"\u2551"
g=f+c+f
ab=g+c+g+c+g+c+f+c+c+f
cadena1=(2*d)+b+(11*c)+a+(2*d)
cadena2= d+b+(13*d)+a+d
cadena3=b+15*e+a
cadena4=2*c+a+2*c+e+c+e+c+e+c+e+c+b+3*c
cadena5=3*d+a+8*c+b+4*d
cadena6=(4*d)+f+c+g+c+g
cadena7=(5*d)+c+c+c+c+c+c+(2*c)+c+(5*d)
print cadena7
print cadena6
print cadena5
print cadena4
print cadena3
print cadena2
print cadena1


Este script dibuja un barquito en la pantalla:
     _________     
    ║_║_║_║_║
   /________\    
__/__■_■_■_■_\___
\■■■■■■■■■■■■■■■/
 \             / 
  \___________/