29 septiembre 2007

Jugando con Perl (6)

Otra de las novedades de Perl frente a otros lenguajes "clásicos" es el soporte de "tablas hash", una estructura de datos parecida a los "arrays", pero en la que para acceder a cada elemento no usaremos un número, sino una palabra asociada.

Las variables de tipo "hash" se declaran precediendo su nombre por un símbolo de porcentaje (%). Una primera forma de definirlas, bastante compacta, es ésta:

%edad = ('Juan', 23, 'Pedro', 31);

Para ver la edad de Pedro haríamos

print "La edad de Juan es " . $edad{'Juan'} . "\n";

(cuidado: para acceder a cada dato individual sí se emplea $, y la referencia que buscamos se encierra entre llaves).

Existe otra forma de declarar este tipo de variables, que ocupa más espacio pero puede resultar más legible:

%estatura = (
Juan => 182,
Pedro => 178
);

Así se ve más claramente que son dos pares de datos.

En este caso, también se accedería a cada dato de la misma forma

print "La estatura de Pedro es " . $estatura{'Pedro'} . "\n";

Se puede modificar el valor de una variable de tipo hash así:

$estatura{'Juan'} = 183;

Si usamos este mismo formato con una referencia que no existe, se añadirá a la tabla hash:

$estatura{'Alberto'} = 169;

Podemos borrar un dato con delete:

delete $estatura{'Juan'};

O eliminar todo el hash con "undef":

undef %estatura;


Finalmente, podemos juntar todo esto en un pequeño programa de prueba:

%edad = ('Juan', 23, 'Pedro', 31);
print "La edad de Juan es " . $edad{'Juan'} . "\n";
%estatura = (
Juan => 182,
Pedro => 178
);
print "La estatura de Pedro es " . $estatura{'Pedro'} . "\n";
$estatura{'Juan'} = 183;
print "La estatura de Juan es " . $estatura{'Juan'} . "\n";
$estatura{'Alberto'} = 169;
delete $estatura{'Juan'};
print "La estatura de Juan es " . $estatura{'Juan'} . "\n";
undef %estatura;
print "La estatura de Juan es " . $estatura{'Juan'} . "\n";


En este ejemplo, los dos últimos "print" muestran "La estatura de Juan es" y nada más, porque no hay definido ningún valor que mostrar.

28 septiembre 2007

Presentaciones desde Google Docs

A Google Docs todavía le falta mucho para ser perfecto. Ya va siendo razonablemente utilizable, pero me fastidia , más que la carencia de ciertas posibilidades, el que aún tenga malos detalles en algunas de las soportadas.

Por ejemplo, no me gusta que el documento que ves en pantalla y el PDF que generas a partir de él sean "tan distintos". Los grandes espacios entre párrafos típicos de HTML no se ven en pantalla pero sí en el PDF, por lo que cuesta afinar para conseguir la apariencia que buscas.

En cualquier caso, la herramienta no para de crecer. Hoy me ha sorprendido ver propaganda de Google Docs en una búsqueda normal en Google, he seguido el enlace y he visto que ya incluyen una herramienta para crear presentaciones (supongo que desde hace poco tiempo, o al menos yo lo había pasado por alto hasta ahora... y me imagino que no soy el único, o no lo anunciarían):



Como era de esperar, está a años luz de las últimas versiones de Powerpoint en cuanto a funcionalidades: no existen animaciones, no se pueden poner notas, las posibilidades de ajuste de la apariencia son muy limitadas...

Pero para un usuario básico, lo fundamental sí está: crear diapositivas (desde cero o duplicando una anterior), usar varios temas (diseños) distintos, incluir recuadros de texto, cambiar la apariencia del texto, incluir imágenes...

Y para ciertos tipos de usuarios concretos: varias personas pueden editar la presentación a la vez... pero también varias personas (a través de Internet) pueden ver la presentación en el mismo momento.

Curiosamente, permite importar ficheros PPT (Powerpoint), pero no exportarlos (al menos no todavía). Eso sí, tiene una "vista imprimible" por si queremos volcar a papel o a PDF (con una utilidad de terceros), y también una opción "Guardar como .zip", que crea una página web (con sus ficheros auxiliares) que podríamos ver desde nuestro ordenador, sin conexión a Internet.

Claramente, esta herramienta no apunta exactamente al mismo sector que Powerpoint. Los "power users" de las presentaciones requerirán mucho más. Pero quien necesite una herramienta colaborativa, puede tener aquí un gran aliado.

27 septiembre 2007

Jugando con Perl (5)

Una de las grandes ventajas de Perl sobre otros lenguajes "más antiguos" como C es el manejo más sencillo de cosas frecuentes, como las cadenas de texto. Otro es la enorme cantidad de funciones incorporadas, que permiten hacer gran cantidad de cosas con una cierta sencillez. Otro es el uso de expresiones regulares directamente desde el lenguaje. Eso es lo que vamos a ver hoy: las expresiones regulares, y de paso, algo más sobre el manejo de cadenas.

En C, para ver si una cadena empieza por "a", haríamos algo como

if (texto[0] == 'a') ...


Si queremos ver si empieza por "ab", la cosa se va haciendo más engorrosa

if ((texto[0] == 'a') && (texto[1] == 'b')) ...

Esto, además de ser más largo y más difícil, tiene "problemas menores": ¿si mi cadena tiene sólo longitud 1, debería yo acceder a la segunda posición? La mayoría de los compiladores, si no se cumple la primera parte de una condición unida por &&, no se molestarían en seguir comprobando, pero... ¿y si mi cadena es "a"? Podría ir afinando un poco la comparación haciendo

if ((strlen(texto) >=2) && (texto[0] == 'a') && (texto[1] == 'b')) ...

Está claro que apenas una comparación tan sencilla como "empieza por ab en minúsculas" ya va siendo engorrosa de programar en C.

En Perl todo esto es mucho más sencillo, gracias al uso de expresiones regulares. Vamos a ver cómo se haría y luego detallamos qué hemos hecho:

$frase1 = "abcde";

if ($frase1 =~ m/ab.*/) {
print "La frase 1 contiene ab y quizá algo más\n";
}


Cosas a tener en cuenta para empezar:
  • Para comparar una cadena con una expresión regular usaremos =~ (si queremos ver si cumple la condición) o !~ (para comprobar si NO se cumple).
  • La expresión regular se indica entre / y /
  • La operación más sencilla con cadenas es comparar ("match"), así que antes de la primera barra añadiríamos una m.
  • Un punto (.) quiere decir "cualquier carácter".
  • Un asterisco (*) quiere decir "el carácter anterior, repetido 0 o más veces".

(luego en la expresión anterior estamos buscando: a, b, 0 o más veces cualquier carácter).

Si eso queda claro, sigamos...

Para ver si se ha tecleado en mayúsculas o en minúsculas, usaríamos corchetes. Los corchetes indican opcionalidad, es decir, que nos sirve cualquiera de los elementos que indicamos entre ellos:

$frase2 = "aBcde";

if ($frase2 =~ m/[aA][bB].*/) {
print "La frase 2 contiene ab (mayúscula o minúscula) y quizá algo más\n";
}


Si se trata de un rango de valores, podemos usar un guión. Por ejemplo, podríamos comprobar si se ha tecleado un número, haciendo

$numeroEntero = "12345";

if ($numeroEntero =~ /[0-9]*/) {
print "El número entero sólo contiene cifras\n";
}


(0 o más cifras del 0 al 9)

Pero siendo estrictos, eso daría una cadena vacía como número válido, y eso es un tanto discutible. Si queremos que al menos haya una cifra, en vez de usar el asterisco (0 o más), usaríamos el símbolo de la suma (+), que indica "1 o más veces":

if ($numeroEntero =~ /[0-9]+/) {
print "El número entero sólo contiene cifras\n";
}


(1 o más cifras del 0 al 9)

Realmente, esto aceptaría cualquier cadena que contenga un número entero. Si queremos que SÓLO sea una número entero, podemos indicar el principio de la cadena con ^ y el final de la cadena con $, de modo que haríamos

if ($numeroEntero =~ m/^[0-9]+$/) {
print "El número entero sólo contiene cifras\n";
}

(la cadena contiene sólo 1 o más cifras del 0 al 9)


¿Cómo lo haríamos para un número real? 1 o más cifras del 0 al 9, seguidas quizás por un punto decimal (pero sólo 1) y, en ese caso, seguidas también por 1 o más cifras del 0 al 9.

Para eso necesitamos saber alguna cosa más:
  • El "." es un comodín, de modo que si queremos buscar si aparece un punto dentro de nuestra cadena, deberemos indicar que no nos referimos al comodín, sino al símbolo del punto ("."), y para eso lo precedemos con la barra invertida: \
  • Si queremos que algo se repita como mucho una vez (0 o 1 veces), añadiremos una interrogación ("?") a continuación.
  • Si necesitamos agrupar cosas (que se repita "el punto y una secuencia de cifras") lo haremos usando paréntesis antes del símbolo "?" (o el que nos interese en nuestra comprobación).

Con esas consideraciones, lo podríamos escribir así:

if ($numeroReal1 =~ m/^[0-9]+(\.[0-9]+)?$/) {
print "El número real 1 parece correcto\n";
}


Un ejemplo que agrupe todo esto:

------

$frase1 = "abcde";
$frase2 = "aBcde";
$numeroEntero = "12345";
$numeroEnteroFalso = "123a45";
$numeroReal1 = "123.45";
$numeroReal2 = "123.4.5";
$numeroReal3 = "123.";

if ($frase1 =~ m/ab.*/) {
print "La frase 1 contiene ab y quizá algo más\n";
} else {
print "La frase 1 no contiene ab\n";
}

if ($frase2 =~ m/ab.*/) {
print "La frase 2 contiene ab y quizá algo más\n";
} else {
print "La frase 2 no contiene ab\n";
}

if ($frase2 =~ m/[aA][bB].*/) {
print "La frase 2 contiene ab (mayúscula o minúscula) y quizá algo más\n";
} else {
print "La frase 2 no contiene por ab (mayúscula o minúscula)\n";
}

if ($numeroEntero =~ m/^[0-9]+$/) {
print "El número entero sólo contiene cifras\n";
} else {
print "El número entero no sólo contiene cifras\n";
}

if ($numeroEnteroFalso =~ m/^[0-9]+$/) {
print "El falso número entero sólo contiene cifras\n";
} else {
print "El falso número entero no sólo contiene cifras\n";
}

if ($numeroReal1 =~ m/^[0-9]+(\.[0-9]+)?$/) {
print "El número real 1 parece correcto\n";
} else {
print "El número real 1 no parece correcto\n";
}

if ($numeroReal2 =~ m/^[0-9]+(\.[0-9]+)?$/) {
print "El número real 2 parece correcto\n";
} else {
print "El número real 2 no parece correcto\n";
}

if ($numeroReal3 =~ m/^[0-9]+(\.[0-9]+)?$/) {
print "El número real 3 parece correcto\n";
} else {
print "El número real 3 no parece correcto\n";
}


-----

que daría como resultado:

La frase 1 contiene ab y quizá algo más
La frase 2 no contiene ab
La frase 2 contiene ab (mayúscula o minúscula) y quizá algo más
El número entero sólo contiene cifras
El falso número entero no sólo contiene cifras
El número real 1 parece correcto
El número real 2 no parece correcto
El número real 3 no parece correcto


Otras posibilidades que no hemos comentado (los ejemplos, más abajo):
  • Si queremos que la búsqueda no distinga entre mayúsculas y minúsculas, añadiremos una "i" a continuación de la segunda barra,
  • Para expresar que algo debe repetirse un número concreto de veces, lo indicamos entre llaves: {2,4} querría decir "un mínimo de 2 veces y un máximo de 4 veces"; {3} sería "exactamente 3 veces"; {7,} indicaría "7 o más veces".
  • Una barra vertical ("|") indica opcionalidad.
  • Un acento circunflejo ("^") nada más comenzar un corchete indica que buscamos el caso contrario.


Algunos ejemplos más, para poner casi todo a prueba:

  • Una secuencia de una o más letras "a": /a+/
  • Una secuencia enre 3 y 5 "a": /a{3,5}/
  • Cualquier letra: /[a-zA-z]/
  • Una secuencia de cero o más puntos: /\.*/
  • Una secuencia de letras "a" o "b": /[a|b]+/
  • Las palabras "Jorge" o "Jorgito": /Jorg(e|ito)/
  • Las palabras "Pedro", "pedro", "Juan", "juan": /[Pp]edro|[Jj]uan/
  • Las palabras "Pedro" o "Juan", en mayúsculas o minúsculas: /Pedro|Juan/i
  • Cualquier cosa que no sea una cifra: /[^0-9]/

Finalmente, quizá sea interesante comentar que para ahorrarnos trabajo en cosas frecuentes como "cualquier cifra" tenemos abreviaturas similares a "\d". Estas son las más habituales:

\d  Un dígito numérico
\D un carácter que no sea un dígito numérico
\w Un carácter "de palabra" (alfanuméricos y "_")
\W Un carácter "no de palabra" (opuesto al anterior)
\s Un carácter de espacio en blanco
\S Un carácter que no sea de espacio en blanco
\t Un tabulador
\n Un avance de línea
\r Un retorno de carro
\043 Un carácter indicado en octal (en este caso, 43 octal = 35 decimal)
\x3f Un carácter hexadecimal (éste es 3f hexadecimal = 63 decimal)

(Se puede hacer más cosas aún, pero como introducción es bastante...)

26 septiembre 2007

Lazarus avanza hacia el 0.9.24

Lazarus, la alternativa Open Source a Delphi, lleva desde marzo de 2007 (ya casi 6 meses) sin "cambios visibles". ¿O debería decir "sin una nueva versión"? Porque avanzar SÍ avanza...

Para aquellos que lo usamos, ahora hay una forma rápida de tener respuesta a preguntas como ¿para cuándo la próxima versión? El equipo de desarrollo ha abierto un Blog (en inglés, como era de esperar), en el que responden a preguntas como ¿cuándo la versión 0.9.24?

Como era de esperar, todavía no hay respuesta para esta pregunta, pero sí buenos indicios: quedan 23 bugs por resolver en la versión "beta", pero ya se han eliminado cerca de 200 desde la primera entrega, y se han hecho unas 1.300 modificaciones (envíos al repositorio SVN, siendo un poco más concretos).

También comentan otros detalles, como que desde hace poco se apoyan en Free Pascal 2.2.0, y muestran algunas estadísticas, como que el tráfico generado por la descarga de "Snapshots" (versiones "nocturnas" todavía en fase de pruebas) fue de 50 GB durante agosto... eso supone más de 30.000 descargas, es decir, más de 1.000 descargas cada día, nada mal para tratarse de versiones "no estables". El 43% de las descargas son ya para Windows. ¿Estará Lazarus llegando ya "al pueblo llano"? (Vale, vale, reconozco que yo también lo uso desde Windows...)

Por cierto... el Blog es lazarus-dev.blogspot.com

24 septiembre 2007

Somos tus colegas

Eso aparentan ciertos profesores el primer día de clase. "Vamos a ver una serie de conceptos que van a ser importantes para vuestro futuro profesional". Quieren que les llames por un diminutivo en vez de por su nombre completo. Las clases son en tono distendido... "Cómo mola, qué tíos más enrollados".

Pero llega el día del examen y no se trata de demostrar que has asimilado conceptos. No importa que hayas asistido a todas las clases ni que hayas participado incluso ampliando lo que dice el profesor con tus experiencias personales en la empresa privada. No importa que hayas asistido a todas las sesiones de prácticas y que hayas realizado correctamente todas las prácticas que pedían.

El día del examen te encuentras con que si no apruebas la práctica no te corrigen la teoría. Y la parte práctica es un examen escrito (!!!!), corregido por otro profesor que no es el que te las impartió. Un examen en el que te piden cosas como que escribas (!!!!) tu implementación del DAO (para los profanos, los "objetos de acceso a datos", que enmascaran el acceso a la base de datos para que el resto del programa no se preocupe de detalles "feos").

Y tu piensas "¿Perdón? Pero si mi DAO, a pesar de ser apenas una estructura básica usada para hacer pruebas, son 9 ficheros, con unas 500 líneas totales de código en Java". Por cierto... esta asignatura no iba sobre DAOs, no es una asignatura de programación, eso era sólo una excusa para completar el proyecto y probar el uso del CVS (o eso dijo el profesor de prácticas). "¿De verdad espera que le plante las 500 líneas de Java? No puede ser. Le contaré la estructura de carpetas que he creado y lo que hace cada clase..." Gran error. Quiere que le escribas línea por línea el código de tu implementación (!!!!).

Por si acaso, en la teoría te preguntan qué era esa palabra que sólo se menciona una vez, que está en inglés y que tiene una traducción difícil, para que ni siquiera saber el hecho de inglés te pueda ayudar mucho a recordarla. Pero eso no importa, porque como no apruebas la práctica no llegan a corregirte la teoría.

¿Resultado? De los que estábamos allí para revisar el examen, sólo he visto una persona que haya obtenido más de un 1,5. (1,5 sobre 10 ¿realmente esa cantidad de gente no ha asimilado más de un 15% de los conocimientos que intentaban transmitirles? Si tuvieran vergüenza, esos resultados deberían frustarles).

Y esto pasa en 5º curso de carrera.

En primer curso entiendo (aunque no comparto esa teoría) que haya algún profesor que "meta caña" para que los alumnos que no tienen realmente interés dejen la carrera y no haya masificación. Lo veo totalmente antipedagógico, ridículo en el siglo XXI. Ya que hay unos baremos para que no todo el mundo entre a la universidad, deberíamos formar a los que entran, en vez de hacer una segunda criba. Pero no... vamos a ver si encontramos la forma de que suspendan, algo tiene que haber que no recuerden y que nos dé la excusa que buscamos... incluso en quinto curso.

Pues suerte que están ahí para ayudarme a aprender y que además son mis colegas, porque si no lo llegan a ser...

Que asco de universidad... ¿quien me manda a mí codearme con esa panda de impresentables sin necesitarlo...?

21 septiembre 2007

Adiós, Universidad

Creo que voy a dejar los estudios. Abandono la universidad. A mis "taitantos" años voy a engrosar las listas del fracaso escolar en este país en el que me tocó nacer.

Y puede sorprender, estando en último curso y habiendo obtenido una nota media de 8,2 en la convocatoria de Junio, a pesar de trabajar a jornada completa. Y más si se piensa que en las pocas asignaturas en las que no he trabajado en un grupo asignado, sino que he dependido de mi propio esfuerzo, mi media ha sido de 9. No soy el alumno más brillante de mi facultad, pero tampoco soy mal estudiante... y aun así, me rindo.

Pero es que no todo ha sido un camino de rosas. Ha habido asignaturas que he suspendido (pocas, afortunadamente).

Por ejemplo, en la media anterior no he contado LA (sí, una) que suspendí en junio. Una asignatura de último curso. Un examen de desarrollo con preguntas ambiguas... corregido con plantilla. Y daba igual que tu respuesta fuera razonable para lo que preguntaban. Como no era la respuesta que ellos querían, es incorrecta, aunque la ambigüedad del enunciado diera pie a más de una interpretación.

Y en esa asignatura me he vuelto a examinar en septiembre, he hecho un examen mejor... pero parece que la he vuelto a suspender... y esta vez con un 1. En las demás asignaturas no bajé del 7,1 y en esta obtengo un 1. Algo no cuadra. Además, más del 50% del temario coincide con el de otra asignatura que superé en otra universidad hace 3 años, y otro 20% coincide con cosas con las que he trabajado en la empresa privada y/o he realizado cursos de formación. Pero a pesar de eso, esta señora opina que mi aprovechamiento de su asignatura es de un 10%. Perdón, no debería llamarla "señora", porque no se ha ganado mi respeto, así que lo dejaremos en "persona".

No es la única asignatura con criterios de evaluación "sorprendentes". También he visto cómo en 4º curso de carrera se me tachaba una pregunta entera a pesar de que el desarrollo fuera correcto, porque un dato estaba mal transcrito y el profesor me dijo "es que no sé si has cambiado ese dato a propósito para que te salga más fácil". ¿A qué estamos jugando?

Supongo que los demás alumnos no se quejan de este tipo de cosas por miedo a represalias, pero no es mi caso. Yo no necesito el título, estudio por hobby. Esta carrera no me va a permitir llegar más alto en mi profesión.

Por cierto, hablo con conocimiento de causa porque... YO SOY PROFESOR. Eso sí, no soy profesor universitario, sino de Enseñanza Secundaria. No tengo una licenciatura universitaria, como esta "persona", pero sí dos diplomaturas (bueno, casi tres). Y no obtuve mi plaza gracias a baremos dudosos ni a amiguismos, sino que superé una oposición (a la primera, por cierto, y sin ayuda de academias, sino preparando yo mis propios apuntes mientras trabajaba en la empresa privada).

Pero las estadísticas de esta "persona" y las mías son muy distintas. Mientras que ella (y algún otro) no llegan al 15% de aprobados, más de un 93% de mis alumnos superó el curso en Junio, y lo hicieron con una nota media de 7,066. Alguien debería recordar a esta "persona" (y a los que siguen su ejemplo) que las notas de los alumnos TAMBIÉN EVALÚAN AL PROFESOR. Si yo sólo consiguiera que un 15% de los alumnos de último curso asimilaran lo que intento enseñarles, me sentiría muy frustrado.

Pero estas personas y yo tenemos conceptos muy distintos de la enseñanza... afortunadamente para mis alumnos.

De hecho, alguien que juega así con el tiempo y el desencanto de alumnos de último curso, ni siquiera merece que se le llame "persona", así que pido perdón si he ofendido a algún alumno, y lo dejaré en "ser".

Quizá estoy hablando de más y ese desconcertante "1" que he visto en mi expediente es sólo un error de transcripción. Quizá ese "ser" esta vez haya corregido con relación a lo que ha enseñado. Quizá cuando vaya a revisión se aclare todo. Pero eso no quitará que son más de las 4 de la mañana y el disgusto que me ha provocado esta "persona" ha conseguido desvelarme. Y no me merece la pena jugar con mi salud por algo que no necesito (pobres de aquellos que sí lo necesitan). Así que quizá sí siga estudiando. Quizá incluso lo haga algún día en esta peculiar universidad, en la que he encontrado más de un profesor que no dominaba lo que enseñaba, más de uno que no sabía explicar, más de uno que pone su labor investigadora muy por encima de su labor docente... Pero sólo quizá.

En cualquier caso, es muy triste que alguien a quien le gusta estudiar tenga que pensar "quizá siga estudiando". Claramente, algo no funciona en la educación en este país.

16 septiembre 2007

Jugando con Perl (4)

(Volvemos tras un pequeño paréntesis vacacional...)

Hemos visto el manejo básico de las condiciones "if" y "while", pero estas órdenes dan más juego del que parece:

Para que el código fuente sea más legible, tenemos también órdenes parecidas pero que comprueban el caso contrario, como

unless (condición) {órdenes}

(las "órdenes" se ejecutaran en caso de que NO se cumpla la condición).

De igual modo, existe una orden similar a while, pero que repite mientras las condición no se cumple (o "hasta que la condición se cumpla"):

until (condición) {órdenes}

Además, estas 4 ordenes (if, while, unless, until) se pueden usar también como modificadores, al final de otra orden:

$y =5 if ($x <>
$y -- unless ($y==0);
print $y while($y <10);
...

pero hay más: también podemos encadenar varios "if" con "elsif":

if ($x <>
elsif ($x > 0) print "Es positivo";
else print "Es cero";

Si alguien viene de C y echa en falta "break" y "continue", también tiene equivalencias:

  • "last" hace lo que el "break": termina el bucle (for, while o el que se esté usando).
  • "next" equivale a "continue": termina la iteración actual del bucle y comienza la siguiente pasada.
  • También existe "redo", que da una nueva pasada sin volver a comprobar la condición.

Por cierto, la orden "goto" existe, pero como su uso es evitable casi siempre, no comento mas sobre ella... ;-)

15 septiembre 2007

Índice del blog

Como el índice por fechas puede resultar un poco caótico para encontrar cosas, voy a añadir un índice por temas, de modo que sea algo más fácil encontrar lo que se busque...


Programación en C#

Culturilla informática y otras curiosidades

Programación en C

Compiladores y otras herramientas software
Hardware


Bases de datos


Programación en Perl

Opinión en general