Story Transcript
Curso de C# Tercer artículo del curso que, mediante un programa, nos introducirá en las sentencias de control y permitirá aplicar los conceptos aprendidos hasta ahora. Este mes tenemos una clase práctica. De esta forma podremos "sedimentar" lo que hemos aprendido ya y, de paso, conocer los bucles y las sentencias de decisión. No hace falta decir que vamos a seguir viendo clases ¿verdad?. Hola a tod@s un mes más. En esta ocasión, y cumpliendo lo prometido en la primera entrega del curso, vamos a ser "originales". Vamos a programar, y además vamos a programar algo útil y que se utiliza mucho en informática, sobre todo en el área de Internet. Hablo de la codificación a Base64. Muchos de vosotros ya sabréis de qué hablo, otros no, pero seguro que google saca de dudas a más de uno. Ciertamente es una codificación que se usa mucho en autentificación HTTP, en correo electrónico, en las claves y firmas PGP, en las cookies, en los foros....... baste decir que en los correos electrónicos se usa para codificar elementos binarios dentro de ellos (como virus, imágenes, ejecutables y otras cosas). Haz la prueba: abre el código fuente de un correo electrónico que tenga, por ejemplo, una imágen adjuntada y verás algo parecido a esto: Content-Type: image/gif; name="=?iso-8859-1?Q?Humor_Grafico.gif?=" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="=?iso-8859-1?Q?Humor_Grafico.gif?=" R0lGODlhDgHIAPcAAAAAAP///wAAAA+QQE6AMAACwAAAAADgHIAEAI/wADCBxIsKDBgwgTKlzIsKHDhxAjSpxIsaLF E6AiODzmEh0lhDgxgzE6AatzIsaPCwAAzmEh0CyAE6AAH .......................................... 6aEh0j88eA0lIsaPa5QeQnTQaDukHCyICwAAAAaPYaAeaMVGqCwAAAAIsaPUhgICADs= Como puedes observar, la imágen (un gif en este caso) viene en texto plano y codificada en base64. Si queréis información sobre la codificación a base64, podéis acudir a muchos links. Yo partí de éste: http://rfc.net/rfc2440.html#s6.3. (el punto final va incluido en la dirección). Lo primero: conocer el algoritmo de codificación a implementar. Bien, pues para hacer un programa que codifique tendremos que conocer el algoritmo. En el enlace que os he puesto viene explicado y lo encontrarás en muchos más sitios, aunque lo voy a explicar de una manera muy resumida. El proceso comienza pasando los caracteres a codificar a su representación ASCII, después los pasamos a binario, con lo que conseguimos una ristra de bytes. Esta cadena de bytes la separaremos de 6 en 6 bits (complementando con ceros por la derecha si nos faltan) y los pasamos de nuevo a su representación decimal. Con estos números, acudiremos a la tabla de conversión que podéis ver en la figura 1 y obtendremos los caracteres codificados en base64. Para finalizar, la longitud de la cadena una vez codificada debe ser múltiplo de 4. Si no es así, rellenaremos con el símbolo '=' hasta que esto se cumpla.
Figura 1 Veamos un pequeño ejemplo. Supongamos que queremos codificar la palabra "arroba" ;-) Tenemos que a=97=01100001, r=114=01110010, o=111=01101111 y b=98=01100010 por lo que obtenemos lo siguiente: 01100001 - 01110010 - 01110010 01101111 - 01100010 - 01100001 que separado en "trozos" de 6 bits, empezando por la izquierda nos queda: 011000 010111 - 001001 - 110010 - 011011 - 110110 - 001001 - 100001. Estos números pasados a decimal nos dan: 24, 23, 9, 50, 27, 54, 9 y 33. Si acudimos a la tabla de la figura 1, obtenemos finalmente la cadena codificada: YXJyb2Jh Vale, ya tenemos claro el algoritmo, así que manos a la obra. En el listado 1 tenemos el programa completo para que lo veas "globalmente" pero lo vamos a comentar paso a paso ya que así aprenderemos conceptos nuevos que aún no hemos tratado.
Empecemos a revisar el programa. Como podemos ver, vamos a hacer uso de System y así lo especificamos en la clausula using, cosa que ya nos suena ¿verdad?. Nuestra clase principal se llama a_base64 (que es como he llamado al fichero que contiene el fuente. Es una costumbre mía, nada más) y en ella definimos inmediatamente la función Main(). Recordad que la definimos static para que sea el punto de entrada del programa. Si no la definiéramos así, para poder ejecutarla necesitaríamos tener creada una instancia de la clase y no podemos sin un programa que la cree (la pescadilla que se muerde la cola). Vale, pero tenemos una novedad en nuestra función Main() y es que tiene un parámetro de nombre args y de tipo String[]. Esto quiere decir que el programa acepta argumentos de tipo cadena (todos los argumentos pasados desde la consola se toman como string). Además puede aceptar más de uno (de ahí los []) por lo que estamos hablando de una tabla (o array, o matriz, como más os guste) de cadenas de texto (string). Una tabla es un tipo especial de variable, con un índice para acceder a sus elementos, que puede almacenar uno o varios datos de un tipo. Si queremos declarar una variable de este tipo podemos hacerlo de varias formas: [] Este es el caso de nuestra función Main(). De esta forma. la tabla no almacena nada, valdrá null si no le pasamos un argumento a nuestro programa desde la linea de comandos. Para declarar y crear una tabla dentro de un programa, también podemos hacerlo creando una instancia del objeto ya que los tipos de datos son objetos, ¿recordáis?: [] = new []; Por ejemplo: si queremos una tabla que almacene 50 objetos de tipo double lo haríamos así: double[] tabla = new double[50]; O también podemos hacerlo así: double[] tabla; tabla = new double[50]; Esta última variante tiene la ventaja de que podremos cambiar dinámicamente el número de elementos de la tabla asignándole otra tabla. Aún así, es importante precisar que una tabla no se puede redimensionar, sino que cuando se le asigna una tabla de otro tamaño, sus elementos son sobreescritos por los de la tabla nueva. Todavía existen otros métodos para declarar tablas de forma que inicialicemos sus valores al mismo tiempo y sin necesidad de indicar el número de elementos (aunque es opcional) ya que el compilador lo deduce de la propia declaración: int[] tabla1 = new int[] {7,3,6,10,56,45}; int[] tabla2 = {7,3,6,10,56,45}; Para acceder a los elementos de la tabla usaremos el índice o posición que queremos obtener (entre corchetes). En C# la primera posición es la 0. Si intentamos acceder a un elemento fuera del rango del índice, obtendremos una excepción de tipo System.OutOfBoundsException. Pero tranquilos, siempre podemos saber dinámicamente cuantos elementos tiene una tabla mediante la propiedad Length de la misma (es un tipo, por lo tanto un objeto, con la propiedad Length entre otras) que, como habréis deducido devuelve la longitud ó número de elementos de la tabla. Pues bien, ya sabemos algo más. Resulta que nuestra función Main() acepta una serie de argumentos de tipo string que podemos evaluar. En el primer y único argumento que vamos a utilizar en nuestro programa, pasaremos la palabra a encriptar. Siguiendo con el listado 1, vemos como declaramos tres variables: dos de tipo string y una entera. La variable cbinario contendrá el número binario de cada carácter de la palabra a codificar, y la variable cCadena irá acumulando esas representaciones binarias todas juntas. Más tarde comprenderemos para qué utilizaremos la variable restocCadena. Seguidamente comienza el programa en sí. Lo que hacemos en la sentencia if (args.Length != 1) es verificar que sólo estemos recibiendo un argumento desde la consola. Una sentencia if es una sentencia de control de flujo, es decir, tomamos una decisión a partir de una condición. Si al evaluar la expresión que sigue al if y que va entre paréntesis, obtenemos un valor true se ejecutará el bloque o sentencia que hay a continuación. Si obtenemos un valor false no se ejecutará ese código y se continuará con el flujo del programa. Pero la sentencia if puede llevar una clausula else (como es el caso de nuestro programa) y en ese caso, si la expresión de la condición devuelve false, se ejecutará el bloque o instrucción posterior al else. En nuestro programa, si no recibimos exactamente un argumento, se imprime por pantalla un mensaje informativo con la sintaxis correcta para después devolver al sistema un valor cero. Esto último en realidad no era necesario, pero al declarar la función Main como int y no como void, estamos obligados a devolver un entero, circunstancia que podremos utilizar en nuestros programas para devolver un código de error entero al sistema en caso de producirse para usarlo, por ejemplo, en scripts bash o BAT. En caso de recibir un único argumento, continua el programa (podéis observar que todo el resto del código está dentro del bloque del else).
Comenzamos con la conversión. Empezamos escribiendo un título y también la palabra a convertir. Podéis ver que está almacenada en la primera posición de la tabla (args[0]). Seguidamente creamos un objeto (oBin) de la clase DectoBin. Esta clase está definida al final del código y, de momento, sólo nos interesa saber que esta clase contiene un método que convierte a binario el entero que le pasemos como parámetro. Ya la estudiaremos al final. Ahora que ya tenemos la palabra a codificar, vamos a recorrerla carácter a carácter mediante un bucle. Y vamos a utilizar un bucle for. Los bucles en programación son un concepto indispensable. Nos permiten repetir bloques de sentencias mientras/hasta que se cumpla una condición que se especifica en la propia construcción del bucle. En C# tenemos varios tipos de bucles (concretamente 4), pero de momento veamos el que nos ocupa. Dentro de unas lineas veremos otro tipo de bucle. El formato normal del bucle for es: for (inicializacion; condicion_de_control; iteracion) { instrucciones } La llaves pueden obviarse si sólo vamos a ejecutar una instrucción. En inicializacion ponemos una instrucción para asignar un valor inicial a una variable que controlará el bucle, y que normalmente debe estar dentro de la condicion_de_control. Esta es una expresión booleana cuya evaluación determina si el bucle continúa ejecutándose o no. Finalmente, iteracion permite cambiar el contenido de la variable de control en cada "vuelta" del bucle. Cuando condicion_de_control se evalúa como false, el bucle deja de ejecutarse y el programa continúa con la siguiente instrucción. Así pues, nuestro bucle for (int i=0;i