miércoles, 17 de septiembre de 2008

Expresiones Regulares en Java

Una representación compilada de una expresión regular.

Una expresión regular, especificada por una cadena, debe ser compilada primero en una instancia de esta clase. El patrón resultante puede ser usado para crear un objeto Matcher que puede comparar secuencias arbitrarias de caracteres contra la expresión regular. Toda la lógica para realizar comparaciones reside en el objeto matcher, asi que varios de estos objetos pueden compartir el mismo patrón.

Una secuencia típica de invocación es la siguiente:

Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();

Un método matches es definido en la clase Pattern para conveniencia cuando la expresión regular será usada sólo una vez. Este método compila la expresión y compara la secuencia de entrada en una sola instrucción. La instrucción es equivalente a:

boolean b = Pattern.matches("a*b", "aaaaab");

La clase String también posee un método matches igual que la clase Pattern, el cual permite comparar una cadena con un expresión:

"aaaaab".matches("a*b");

Estas dos últimas formas son equivalentes a las primeras tres instrucciones, excepto que si se repiten varias veces pierde eficiencia ya que no permite que el patrón compilado sea reutilizado.

Instancias de esta clase son inmutables y son seguras para utilizar en procesamiento multihilo. Instancias de la clase Matcher no son seguras para este uso.

Si queremos cambiar la expresión utilizada podemos usar el método usePattern() de la siguiente forma:

Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();

Pattern p2 = Pattern.compile("a*b*"); //compila una expresión
m.usePattern(p2); //se cambia el patrón
boolean b2 = m.matches();

Expresiones Regulares

Clases de Caracteres

[abc] a, b, o c (forma simple)

[^abc] Cualquier caracter excepto a, b, o c (negación)

[a-zA-Z] a hasta z o A hasta Z, inclusive (rango)

[a-d[m-p]] a hasta d, o m hasta p: [a-dm-p] (unión)

[a-z&&[def]] d, e, o f (intersección)

[a-z&&[^bc]] a hasta z, excepto para b y c: [ad-z] (sustracción)

[a-z&&[^m-p]] a hasta z, y no m hasta p: [a-lq-z](sustracción)

Clases de Caracteres Predefinidas

. Cualquier caracter

\d Un dígito: [0-9]

\D No dígito: [^0-9]

\s Un caracter blanco: [ \t\n\x0B\f\r]

\S No caracter blanco: [^\s]

\w Un caracter de palabra: [a-zA-Z_0-9]

\W No caracter de palabra: [^\w]

Cuantificadores

X? X, cero o una vez

X* X, cero o más veces

X+ X, una o más veces

X{n} X, exactamente n veces

X{n,} X, al menos n veces

X{n,m} X, al menos n veces pero no más de m veces

Operadores Logicos

XY X seguido por Y

X|Y X o Y

(X) X, como un grupo

Precedencia

1 Caracter de escape \x

2 Agrupación [...]

3 Rango a-z

4 Unión [a-e][i-u]

5 Intersección [a-z&&[aeiou]]

Metacaracteres:
([{\^-$|]})?*+

Si se desea comparar estos caracteres en las expresiones se debe utilizar alguna de las siguientes formas:

precederlo con un backslash, o
colocarlo entre \Q (que inicia la cita) y \E (que la termina).

Ejemplo:

[\^] ó [\Q^\E] sólo acepta el caracter ^

Clases de Caracteres POSIX (sólo US-ASCII)

\p{Lower} Una letra minúscula: [a-z]
\p{Upper}
Una letra mayúscula:[A-Z]
\p{ASCII}
Todos los caracteres ASCII:[\x00-\x7F]
\p{Alpha}
Un caracter del alfabeto: [\p{Lower}\p{Upper}]
\p{Digit}
Un dígito decimal: [0-9]
\p{Alnum}
Un caracter alfanumérico: [\p{Alpha}\p{Digit}]
\p{Punct}
Signo de Puntuación: Alguno entre !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph}
Un caracter visible: [\p{Alnum}\p{Punct}]
\p{Print}
Un caracter imprimible: [\p{Graph}\x20]
\p{Blank}
Un espacio en blanco o un tabular: [ \t]
\p{Cntrl}
Un caracter de control: [\x00-\x1F\x7F]
\p{XDigit}
Un dígito hexadecimal: [0-9a-fA-F]
\p{Space}
Un caracter blanco: [ \t\n\x0B\f\r]


Ejemplos de Expresiones Regulares

1. Que sólo permita la palabra "hola"

[h][o][l][a]
hola

2. Que permita la palabra "hola" con cualquier combinacion de mayusculas y minusculas

[hH][oO][lL][aA]

3. Que permita una de las cadenas siguientes: col, lol, sol

[cls]ol

4. Que permita cualquier caracter al inicio, excepto “c” “l” “s”. Debe terminar con las letras “o” “l”. Permite gol, mol, etc, etc.

[^cls]ol

5. Que permita un dígito del 1 al 5

[12345]
[1-5]

6. Que permita un dígito que no esté entre el 1 y el 5

[67890]
[^1-5]

7. Que permita los dígitos del 0 al 4 y del 6 al 8 (0,1,2,3,4,6,7,8)

[01234678]
[0-4[6-8]]
[0-46-8]

8. Permita los dígitos del 0 al 4 que estén entre el 3 y el 5

[34]
[0-4&&[345]]
[0-4&&[3-5]]

9. Permite los dígitos del 0 al 9 que no estén entre el 4 y 6

[0123789]
[0-37-9]
[0-9&&[^456]]
[0-9&&[^4-6]]

10. Cero o una Z.Son válidas las cadenas “” y “Z”

Z?

11. Cero o más Z. Son válidas las cadenas “”, “Z”, “ZZ”, “ZZZ”, etc

Z*

12. Una o más Z. Son válidas las cadenas “Z”, “ZZ”, “ZZZ”, etc.

Z+

13. Permita una o más veces la palabra sol: solsolsol

(sol)+

14. Permita la cadena “so” seguida de l o más “l”

sol+

15. Permita las letras abc (en cualquier combinación de longitud 3): aab, bca, ccb, ...

[abc]{3}

16. Permita las letras abc (en cualquier combinación de longitud 3 o más): aabc, bca, ccb, ...

[abc]{3,}

17. Permita las letras abc (en cualquier combinación de longitud entre 3 y 6): aabc, bca, ccb, ...

[abc]{3,6}

18. Permita la palabra “hola” o “adios”

([h][o][l][a])|([a][d][i][o][s])

19. Lenguaje de 0 y 1 que tenga exactamente 2 ceros

[1]*[0][1]*[0][1]*

20 Lenguaje que soporte enteros con o sin signo

[\-+]?[0-9]+

21. Lenguaje de identificadores compuestos por letras y digitos. El identificador debe comenzar con una letra y terminar con letra o digito.

[a-zA-Z][a-zA-Z0-9]*

Internacionalizacion con java.util.ResourceBundle

Esta clase contiene objetos de acuerdo a una localidad específica. Permite que nuestra aplicación se adapte al idioma del ordenador en que se está ejecutando. Si por ejemplo, estuvieramos en una máquina con idioma español, se mostraría el mensaje "hola mundo", si fuera inglés "hello world", y asi para cada idioma que queramos personalizar.

Crear el archivo de propiedades

Como primer paso creamos un archivo con los mensajes que vamos a personalizar, por ejemplo el clásico "Hola mundo". El archivo Mensajes.properties contendrá lo siguiente:

mensaje= Hola Mundo
titulo= Saludo

Obtener una propiedad del archivo

Para cargar el archivo, se hace lo siguiente:

ResourceBundle.clearCache(); //se limpia el cache
ResourceBundle propiedades = ResourceBundle.getBundle("Mensajes");

JOptionPane.showMessageDialog(null, propiedades.getString("mensaje"), propiedades.getString("titulo"), JOptionPane.PLAIN_MESSAGE);

En este caso se mostraría una ventana con el mensaje "Hola Mundo".

Si cambiaramos el contenido del archivo Mensajes.properties a lo siguiente:

mensaje= Hello World
titulo= Greetings

El programa automaticamente sería traducido al inglés. Se mostraría una ventana diciendo "Hello World"

Esto permite que con solo cambiar el contenido del archivo .properties el programa se pueda internacionalizar, sin tener que volver a compilarlo, sin cambiar el codigo.

Para saber si existe alguna propiedad llamada saludo2 podemos hacer lo siguiente:
propiedades.containsKey("saludo2");

Obtener todas las propiedades

Enumeration llaves = propiedades.getKeys();

while (llaves.hasMoreElements()) {
String llave = (String)llaves.nextElement();
String valor = propiedades.getString(llave);
System.out.println("llave= " + llave + ", " +
"valor= " + valor);
}

Esto imprimiria lo siguiente:

llave= mensaje, valor= Hola Mundo
llave= titulo, valor= Saludo

viernes, 29 de agosto de 2008

Uso de la clase java.util.Properties

Esta clase representa un conjunto de propiedades persistentes.

Cuando usamos esta clase pueden ocurrir las siguientes excepciones:
java.io.FileNotFoundException: no se encuentra el archivo
java.io.IOException: ocurrió un problema al leer el archivo

Crear el archivo de propiedades

Para indicar las propiedades se usa la forma nombre=valor, si quisieramos escribir la propiedad en dos lineas tendriamos que usar el simbolo '\'. Los comentarios inician con #.

Para nuestro ejemplo crearemos el archivo propiedades.txt con el siguiente contenido:

# esto es un comentario
edad=15
nombre=Pedro \
Gómez

Para escribir #, !, =, : tienen que estar precedidos por un backslash (\).

Lectura de Propiedades

Para leer una a una las propiedades se hace lo siguiente:

try{
//creamos el objeto para almacenar las propiedades
Properties p = new Properties();
//cargamos el archivo
p.load(new FileInputStream("propiedades.txt"));
//obtenemos las propiedades
System.out.println("nombre = " + p.getProperty("nombre"));
System.out.println("edad = " + p.getProperty("edad"));
}
catch (Exception e) {
System.out.println(e);
}

Recorrido de las propiedades

Para leer todas las propiedades se hace lo siguiente:

try {
//creamos el objeto para almacenar las propiedades
Properties p = new Properties();
//cargamos propiedades, de esta forma podremos añadir y modificar las propiedades de este archivo
p.load(new FileInputStream("propiedades.txt"));
//obtenemos una enumeracion con los nombres de las propiedades
Enumeration propiedades=p.propertyNames();
//hacemos un ciclo para obtener todas las propiedades
while (propiedades.hasMoreElements()){
String propiedad=(String)(propiedades.nextElement())
System.out.println ( propiedad + "= " + p.getProperty(propiedad));
}
}

catch (Exception ex){
System.out.println(ex);
}

El método propertyNames() devuelve una enumeracion con los nombres de las propiedades.
El método nextElement() nos devuelve un objeto diferente la enumeracion en cada iteración del ciclo.

Escritura de Propiedades

try{
//creamos el objeto para almacenar las propiedades
Properties p = new Properties();
//cargamos propiedades, de esta forma podremos añadir y modificar las propiedades de este archivo
p.load(new FileInputStream("propiedades.txt"));
//añadimos propiedades
p.setProperty("direccion","Panama");
//cambiamos la propiedad edad
p.setProperty("edad","20");
//Decimos el nombre del archivo de destino para grabar las propiedades
java.io.FileOutputStream out = new java.io.FileOutputStream("propiedades.txt");
//Grabamos las propiedades en el archivo
p.store(out, "nuevas propiedades");

}
catch (Exception e) {
System.out.println(e);
}

viernes, 22 de agosto de 2008

Lectura de archivos de texto con ActionScript

Primero que nada necesitamos el archivo para leer. Debe tener el siguiente formato:

variable1=contenido1&variable2=contenido2&...variableN=contenidoN

Para nuestro ejemplo usaremos un archivo llamado archivo.txt con el siguiente contenido:

nombre=Juan Perez&telefono=555-5555

Luego, para realizar la lectura utilizamos el siguiente codigo:

//Creamos la variable que leerá el archivo
var datosleidos = new LoadVars();

//Leemos el archivo. Si el archivo se encuentra en un directorio distinto hay que especificar la ruta completa
datosleidos.load("archivo.txt");

//Función que es llamada despues de leer el archivo
datosleidos.OnLoad = function() {
//Mostramos las dos variables del archivo
trace (datosleidos.nombre);
trace (datosleidos.telefono);
};

La funcion trace() solo funciona si estamos probando el archivo en Adobe Flash y no con el FlashPlayer.

Y listo. Con esto se pueden leer archivo de texto de forma sencilla y rápida.

Nota. No se pueden escribir archivos de texto con flash. Para hacerlo se tendria que hacer a través de un script PHP o ASP.

Ejecutar PHP desde Flash

Hay varias forma de ejecutar un script php desde flash. La mas sencilla es la siguiente:

var variable = new LoadVars();
variable.load("escritura.php");

Con esto ejecutamos el script escritura.php

Si queremos enviarle variables al script PHP agregamos un signo de interrogacion (?) y copiamos las variables y sus valores separados por el simbolo &

variable.load("escritura.php?nombre=Juan Perez&telefono=555-5555");

Con esto enviamos las variables nombre y telefono

Para accesar a estas variables en el script PHP utilizamos el arreglo $_GET de la siguiente forma:
$_GET['nombre'] contiene la variable nombre
$_GET['telefono'] contiene la variable telefono

Si además queremos ejecutar instrucciones en flash después de ejecutar el script PHP se escribe el siguiente metodo:

variable.OnLoad = function(){
instrucciones a ejecutar después del script PHP
}

Como se puede observar, es sencillo ejecutar un script PHP desde un código ActionScript.

jueves, 21 de agosto de 2008

Uso de la clase java.awt.Desktop

Esta clase permite a una aplicación Java lanzar aplicaciones asociadas registradas en el ordenador para manejar un archivo o URL.

Las operaciones soportadas incluyen:

  • Lanzar el explorador web por defecto para abrir una URL
  • Lanzar el cliente de correo por defecto
  • Lanzar una aplicación registrada para abrir, editar o imprimir un archivo específico
Esta clase puede ser utilizada desde Java 6.

Lanzar el Explorador Web

import java.net.URI;
import java.net.URISyntaxException;
import java.io.IOException;
import java.awt.Desktop;
import java.awt.Desktop.Action;

public class UsoDeDesktop1 {
public static void main (String args[]) throws URISyntaxException, IOException{

//Se comprueba si la clase es soportada en el ordenador
if (!Desktop.isDesktopSupported()){
System.out.printf ("La clase Desktop no es soportada");
System.exit(0); //Termina la aplicación
}

//Se obtiene el objeto Desktop
Desktop escritorio = Desktop.getDesktop();

//Se crea un objeto URI indicando la dirección web
URI direccion = new URI("http://java.sun.com/javase/6/docs/api/java/awt/Desktop.html");

//Se verifica que se puede utilizar la función de abrir una dirección web en este ordenador
if (escritorio.isSupported(Desktop.Action.valueOf("BROWSE")) )
escritorio.browse(direccion); //Se abre la dirección web
else
System.out.printf ("La función BROWSE no es soportada");

}
}

Abrir y Editar un Archivo

import java.io.File;
import java.io.IOException;
import java.awt.Desktop;
import java.awt.Desktop.Action;

public class UsoDeDesktop2 {
public static void main (String args[]) throws IOException{

//Se comprueba si la clase es soportada en el ordenador
if (!Desktop.isDesktopSupported()){
System.out.printf ("La clase Desktop no es soportada");
System.exit(0); //Termina la aplicación
}

//Se obtiene el objeto Desktop
Desktop escritorio = Desktop.getDesktop();

//Se crea un objeto File indicando el archivo
File archivo = new File("UsoDeDesktop2.java");

//Se verifica que se puede utilizar la función de abrir archivos en este ordenador
if (escritorio.isSupported(Desktop.Action.valueOf("OPEN")) )
escritorio.open(archivo);
else
System.out.printf ("La función OPEN no es soportada");

//Se verifica que se puede utilizar la función de editar archivos en este ordenador
if (escritorio.isSupported(Desktop.Action.valueOf("EDIT")) )
escritorio.edit(archivo);
else
System.out.printf ("La función EDIT no es soportada");

}
}

miércoles, 20 de agosto de 2008

Entrada y salida con la clase java.io.Console

Esta clase posee métodos para acceder a la consola que se encuentre asociada a la JVM (Máquina Virtual de Java) actual.
Nos permite leer cadenas y contraseñas de forma fácil siempre y cuando haya una consola asociada a nuestra aplicación.

Esta clase puede ser utilizada desde Java 6.

Observa el primer ejemplo:

import java.io.Console;

public class UsoDeConsola1 {
public static void main (String args[]){

Console consola= System.console();

//si consola es null significa que no podremos utilizar esta clase
if (consola==null){
System.out.printf ("No existe una consola asociada a esta JVM");
System.exit(0); //Termina la aplicación
}

consola.printf("Ingresa al sistema\n");

String user= consola.readLine("user: ");
char password[] = consola.readPassword("pass: ");

//convierte el arreglo de caracteres en un String
String pass= new String (password);

consola.printf("\nEl usuario introducido es: " + user + ", y el password es: " + pass);
}
}

En este ejemplo, primero se verifica si existe una consola (consola==null). Luego se lee muestra el mensaje "user: " y se espera que el usuario introduzca el nombre de usuario. Luego se muestra el mensaje "pass: " y se lee la contraseña del usuario (pero sin mostrarla).

Como pudiste observar, el método readLine() se utiliza para leer cadenas, y el método readPassword() se utiliza para leer contraseñas sin mostrarlas mientras se escribe. El método readPassword() lee un arreglo de caracteres, por eso se tuvo que convertir a un String antes de imprimirlo. Ambos métodos reciben una cadena para mostrar al usuario.

Otras formas de hacer lo mismo serían:

Ejemplo2:

consola.printf("Ingresa al sistema\n");

String mensaje1="user: ", mensaje2="pass: ";

String user= consola.readLine("%s", mensaje1);
char password[] = consola.readPassword("%s",mensaje2);

En este caso se utilizó la versión de los métodos de lectura que funciona similar al método prinf().

Ejemplo3:

consola.printf("Ingresa al sistema\n");

consola.printf("user: ");
String user= consola.readLine();
consola.printf("pass: ");
char password[] = consola.readPassword();

En este último ejemplo, los mensajes se imprimieron en instrucciones separadas y no en los métodos para leer.

Lectura con la clase java.util.Scanner

Esta clase es un simple escaner de texto que permite procesar tipos primitivos y cadenas usando expresiones regulares.

Un Scanner divide su entrada en tokens usando un patrón delimitador, que por defecto es el espacio en blanco. Los tokens resultantes pueden ser convertidos en diferentes tipos usando los diferentes métodos next.

Esta clase puede ser utilizada desde Java 5.

El siguiente ejemplo permite leer desde la consola:

import java.util.Scanner;

public class UsoDeScanner1 {
public static void main (String args[]){

String nombre, apellido;
int edad;

Scanner sc = new Scanner(System.in); //Se indica que se quiere leer desde consola
System.out.print("Introduce tu nombre, apellido y edad: ");
nombre = sc.next();
apellido = sc.next();

edad = sc.nextInt();
System.out.println("Nombre: " + nombre);
System.out.println("Apellido: " + apellido);
System.out.print("Edad: " + edad);
}
}


Observa que el método nextInt() nos permite leer un tipo int, y el método next() nos permite leer un token (devuelve un String). Hay un método next para cada tipo de dato primitivo. Si se desea leer todos los tokens al mismo tiempo se utiliza el método nextLine().


Ejemplo2:


import java.util.Scanner;

public class UsoDeScanner2 {
public static void main (String args[]){


String mensaje1, mensaje2;

float numero;
Scanner sc = new Scanner("6.5 Hola Mundo\n Nueva Línea"); //Se indica que se quiere trabajar con una cadena fija

numero=sc.nextFloat();
mensaje1=sc.nextLine();

mensaje2=sc.nextLine();
System.out.println("Numero: " + numero);
System.out.println("Mensaje1:" + mensaje1);

System.out.println("Mensaje2:" + mensaje2);
}
}

En este caso, se trabajo con una cadena fija. El método nextFloat() obtiene el valor flotante 6.5, mientras que la primera llamada al método nextLine() obtiene el texto " Hola Mundo". Observa que se incluye el espacio en blanco, ya que el método nextLine() obtiene el texto que no ha sido procesado hasta encontrar un salto de línea o el fin de la cadena. La última llamada a nextLine() obtiene el texto " Nueva Línea".

Como último ejemplo, haremos un Scanner que divida la cadena en tokens usando el simbolo de dolar ( $ ):

import java.util.Scanner;
import java.io.File;

public class UsoDeScanner3 {
public static void main (String args[]) throws java.io.FileNotFoundException{

Scanner sc = new Scanner(new File("cadena.txt"));//Se indica que se quiere trabajar con un archivo de texto

sc.useDelimiter("[$]");

while (sc.hasNext())
System.out.println(sc.next());
}
}

En este ejemplo, leemos desde un archivo de texto la cadena que queremos analizar (se debe controlar la excepción java.io.FileNotFoundException). Observa que utilizamos el método hasNext() para leer todos los tokens como String.
Si el archivo tuviera la cadena Ejemplo$de$Scanner$3 la salida resultante sería:
Ejemplo
de
Scanner
3