Programación en Java SE 6 desde cero: Parte 3
Contenido del API de JAVA
Objetivos
-
Aprender los tipos primitivos y su representación en objeto.
-
Realizar operaciones de Escritura/Lectura sobre archivos.
-
Estudiar los paquetes principales del API estándar de Java.
Wrappers Tipos Primitivos
Todos los wrappers en Java se encuentran ubicados en el paquete java.lang. Y a continuación se enumeran con su correspondiente tipo primitivo:
-
Byte encapsula un tipo byte.
Short encapsula un tipo short.
Integer encapsula un tipo int.
Long encapsula un tipo long.
Float encapsula un tipo float.
Double encapsula un tipo double.
Character encapsula un tipo char.
Boolean encapsula un tipo boolean.
Las clases wrapper tienen las siguientes propiedades:
-
Cada uno contiene un campo simple que almacena el valor del tipo primitivo que encapsula.
El valor del tipo primitivo encapsulado no puede ser cambiado.
Cada clase tiene un constructor que coge el valor del tipo que encapsula.
A excepción del Character, cada clase tiene un constructor que permite la entrada de un String y lo transforma al correspondiente primitivo.
Todos tiene un método value que devuelve el valor encapsulado. Por ejemplo el Integer cuenta con un método intValue() que devuelve el valor que contiene.
Los wrappers cuentan con métodos muy útiles que se emplean a menudo programando que permiten hacer trasformaciones entre los tipos primitivos y las cadenas y viceversa.
I/O Streams en JAVA
Paquete java.io
El paquete java.io contiene una gran variedad de clases que permiten relizar entrada salida de diversos modos en Java, según las necesidades del programa que estemos construyendo. El truco para ser capaz de trabajar a gran nivel con este paquete es comprender la diferencia entre las clases que manejan los streams (flujos) o los que son lectores o escritores, y también comprender la diferencia entre trabajar con los flujos de entrada salida a nivel bajo o nivel alto.
I/O Streams Vs Lectores/Escritores
Mirando el contenido el paquete java.io podemos ver que entre los nombres que encontramos de las clases, podemos diferenciar en dos grandes grupos: InputStream o OutputStream y el grupo Reader y Writer. Las diferencias principales entre ambos son:
Las clases Stream se utilizan para leer o escribir todo tipo de datos binarios.
Los Reader y Writer se utilizan exclusivamente para realizar lectura y escritura de cadenas.
Flujos a bajo y alto nivel
La mayoría de clases de entrada tienen su correspondencia en una clase similar de salida. Por ejemplo el DataInputStream tiene su correspondiente DataOutputStream.
Para demostrar el uso de este tipo de clases, vamos a ver un ejemplo con un Reader que nos mostrará la lectura de un fichero que contiene en una línea el abecedario y las va a imprimir por pantalla:
FileReader in = new FileReader(“abecedario.txt”);
int c = 0;
while((c = in.read()) != -1) {
System.out.print((char) c);
}
En el ejemplo se realiza una lectura de un fichero de texto carácter a carácter, por lo tanto la salida se corresponderá con el contenido del fichero hasta que finalice.
Otro concepto importante es comprender la diferencia entre los flujos a bajo nivel y los que son a alto nivel. Dentro de los flujos se hacen estas dos diferenciaciones y se caracterizan porque:
-
Los de bajo nivel están directamente conectados a los datos.
-
Los de alto nivel están conectados a otro stream existente. (Así conseguimos dotarlo de funcionalidad extra).
Ejemplo de Flujos de lectura y escritura
Por ejemplo, un FileReader es a bajo nivel, porque se conecta al fichero de tu sistema de ficheros. El propósito del FileReader no es formatear los datos en ningún sentido (ni lectura ni escritura), en cambio un BufferedReader, decimos que es de alto nivel, porque se conecta a un FileReader y consigue en vez de leer lo caracteres de uno en uno, leer líneas completas, y las convierte a formato String.
Vamos a ver un ejemplo con FileReader y FileWriter para de un fichero donde se encuentran las estaciones del año, estaciones.txt. Como los datos se encuentran en un fichero y hay que realizar una operación de lectura debemos elegir entre un FileInputStream o un FileReader, en este caso como vamos a leer texto nos decantamos por el FileReader que realiza estas operaciones de forma más sencilla, si fuera un binario como una imagen o documento Word o similar tendríamos que realizar la operación con el FileInputStream.
En nuestro fichero de ejemplo las estaciones están cada una en una línea diferente, a si que necesitamos leer el fichero línea a línea, como esta capacidad no la tiene el FileReader, nos ayudaremos de un stream de alto nivel como es el BufferedReader.
import java.io.*;
public class States {
public static void main(String [ ] args) {
try {
FileReader lector = new FileReader(“estaciones.txt”);
BufferedReader in = new BufferedReader(lector);
String estacion = in.readLine();
while(estacion != null) {
System.out.println(“Estacion: “ + estacion);
estacion = in.readLine();
}
} catch(IOException ex) {
ex.printStackTrace();
}
}
}
En el programa comenzamos instanciando el FileReader, lo que se debe meter en un bloque try – catch ya que puede lanzar una excepción en caso de no encontrar el fichero del que se solicita realizar la lectura. Luego conectamos el BufferedReader al lector que ya esta conectado al fichero y luego gracias a sus métodos leemos las líneas contenidas en el fichero una a una.
Clase java.io.File
La clase File, es una de las que más utilizaremos cuando se trate de trabajar con las clases de paquete java.io y se puede utilizar sola y otras veces en combinación con el resto de clases de este paquete para gestionar los flujos de datos. Esta clase representa un puntero a un fichero o directorio, es el nombre de la ruta hacia algún lugar del sistema de ficheros.
Algunos usos que habitualmente se le dan a la clase File son:
-
Determinar si un fichero existe, utilizando el método exist, que devolverá verdadero o falso.
Analizar los permisos que se tienen sobre un fichero con los métodos canRead, canWrite o canExecute.
Crear un fichero nuevo con el método createNewFile.
Crear un nuevo directorio con el método medir.
Borrar un fichero o un directorio con el método delete.
Ver el contenido de un directorio a través de los métodos list y listFiles.
Streams de bajo nivel en JAVA
A continuación veremos un ejemplo de creación de un fichero y escritura de su contenido con las clases que hemos visto hasta el momento de estos paquetes:
public class FileDemo {
public static void main(String [ ] args) {
File test = new File(“./estaciones.txt”);
if(!test.exists()) {
try {
test.createNewFile();
}catch(IOException e) {
System.out.println(e.getMessage());
return;
}
}
Ahora vamos a aprender a utilizar las clases que permiten trabajar en bytes, que son el otro gran grupo que hemos diferenciado dentro del paquete java.io, y son FileInputStream y FileOutputStream, y representan streams de bajo nivel ya que se conectarán directamente a los ficheros donde vayamos a leer (…InputStream) o a escribir (…OutputStream).
En el siguiente ejemplo se visualiza como se copia un fichero byte a byte.
public class CopyFile {
public static void copy(File src, File dest) throws IOException {
FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dest);
int c;
try {
while((c = in.read()) != -1) {
out.write(c);
}
}finally{
in.close();
out.close();
}
}
Genera un fichero con el Word estaciones.doc y luego ejecuta el programa que realiza la copia byte a byte y abre el nuevo fichero que hemos creado.
En el programa podemos observar que la diferencia fundamental es que ahora copiamos byte a byte, y que si hubieramos decidido utilizar las clases Reader o Writer el ejemplo no hubiera funcionado por la naturaleza del fichero que queremos copiar.
Estas clase que acabamos de ver son de bajo nivel ya que se conectan directamente a los recursos del sistema, pero dentro de las clases que trabajan en bytes también tenemos algunas de alto nivel, como son los DataInputStream y DataOutputStream que permiten trabajar con datos en Java y almacenarnos en ficheros y leerlos de los mismos con gran facilidad.
En el ejemplo siguiente tenemos una clase del tipo de dato que almacena nuestro sistema, Empleado que tiene el identificador de empleado y su nombre, y adicionalmente hemos generado un constructor para crear los objetos de tipo Empleado en nuestro sistema.
public class Empleado {
public int idEmpleado;
public String nombre;
public Empleado(int idEmpleado, String nombre) {
this.idEmpleado = idEmpleado;
this.nombre = nombre;
}
public String toString() {
return idEmpleado + " " + nombre;
}
}
Y contamos con una segunda clase EmpleadoManager que tiene un main y por lo tanto se puede ejecutar esta clase que cuenta con dos métodos que hacen las gestión de empleados a fichero, addEmpleado escribe un empleado a el fichero que indicamos y getEmpleados que devuelve una lista de todos los empleados almacenados en el fichero.
import java.io.*;
import java.util.ArrayList;
public class EmpleadoManager {
public static void addEmpleado(Empleado empleado, File dest)
throws IOException {
FileOutputStream fos = new FileOutputStream(dest, true);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream out = new DataOutputStream(bos);
out.writeInt(empleado.idEmpleado);
out.writeUTF(empleado.nombre);
out.close();
bos.close();
fos.close();
}
public static ArrayList<Empleado> getEmpleados(File source) throws IOException {
ArrayList<Empleado> empleados = new ArrayList <Empleado> ();
FileInputStream fis = new FileInputStream(source);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream in = new DataInputStream(bis);
while(in.available() > 0) {
int idEmpleado = in.readInt();
String nombre = in.readUTF();
Empleado actual = new Empleado(idEmpleado, nombre);
empleados.add(actual);
}
return empleados;
}
public static void main(String [ ] args) {
try {
Empleado primero = new Empleado(1, "Jose Garcia");
Empleado segundo = new Empleado(2, "Pedro Perez");
File fichero = new File("empleados.dat");
addEmpleado(primero, fichero);
addEmpleado(segundo, fichero);
System.out.println(getEmpleados(fichero));
}catch(IOException e) {
e.printStackTrace();
}
}
}
Si nos fijamos en el método main generamos dos objetos de tipo Empleado cada uno con sus datos y los guardamos en el fichero de datos, y luego solicitamos la lectura del fichero.
API Estándar J2SE
Una de las grandes ventajas con las que cuenta este lenguaje sobre otros es que cuenta con un gran conjunto de clases ya programadas que se pueden utilizar y extender. Este motivo nos hace ganar mucho tiempo a la hora de desarrollar ya que contamos con un gran apoyo a la hora de trabajar. A continuación vamos a estudiar las clases principales del API.
Las cadenas en JAVA
Las cadenas son secuencias de caracteres. Las cadenas en Java no son tipos primitivos, son objetos. En el API podemos encontrar tres clases que permiten trabajar con cadenas. Todas se encuentran en el paquete java.lang y son String, StringBuilder y StringBuffer. Las diferencias principales que podemos encontrar entre las tres son:
String representa una secuencia invariable de caracteres. Los literales que entrecomillamos dentro de nuestro código son de tipo String.
StringBuilder representa un conjunto de caracteres que puede variar. Esta clase es similar a la clase String solo que los caracteres pueden ser modificados y la longitud de la cadena puede variar. Los métodos de esta clase no están sincronizados y poder lo tanto no se debe utilizar esta clase en contextos multihilo, donde varios hilos pueden acceder a la misma de forma concurrente.
StringBuffer es una clase exactamente igual que StringBuilder solo que los métodos de esta clase estan sincronizados y por lo tanto se puede utilizar en contexto multihilo.
String en JAVA
La clase de las tres más sencilla de utilizar String, pero normalmente no es muy eficiente cuando necesitamos realizar modificaciones en las cadenas, ya que este objeto no permite modificar el contenido y aunque el lenguaje me permite sustituir, modificar, sumar cadenas y demás, la máquina virtual Java por debajo realiza más operaciones que utilizando una de las otras clases que hemos enumerado.
Java permite transformar los literales en clases de tipo String automáticamente como podemos ver:
String cadena = “Hola mundo”;
Aunque como ya sabemos es posible instanciar un objeto de tipo cadena utilizando alguno de sus constructores:
char[ ] listaCar = {‘a’, ‘b’, ‘c’};
String cadenaDos = new String(listaCar);
Debemos tener en cuenta que el operador == sirve únicamente para comparar tipos primitivos, y como String es un objeto, si no queremos tener resultados inesperados en nuestro código debemos compararlo con un método que tienen todos los objetos y su nombre es equals.
String cadenaComparacion = “Hola”;
if (“Hola”.equals(cadenaComparacion))
System.out.println(“éxito en la comparacion”);
Else
System.out.println(“fallo en la comparacion”);
StringBuilder y StringBuffer en JAVA
Cuando necesitemos trabajar con las cadenas, es decir componerla o modificarlas durante nuestro programa, es muy recomendable trabajar con los objetos StringBuilder o StringBuffer, que cuentan con los mismos métodos y sólo difieren en lo que hemos explicado anteriormente. En el siguiente código se muestra un ejemplo de composición de cadena con la clase StringBuilder:
StringBuilder cadenaComposicion = new StringBuilder(26);
for(char inicial = ‘a’; inicial < = ‘z’; inicial++) {
cadenaComposicion.append(inicial);
}
System.out.println(cadenaComposicion);
Estas clases también nos permiten añadir cadenas en diferentes partes de la cadena inicial no sólo al final como veíamos hace un momento. Por ejemplo con el método insert podemos hacerlo en otras posiciones de las cadenas:
StringBuffer sb = new StringBuffer();
sb.append("po").insert(2,"si").insert(0,"com").append("cion");
System.out.println(sb);
Estas clases también contienen otros métodos que permiten realizar manipulación de su contenido como son:
delete(int start, int end), que permite borrar el contenido especificado entre los índices que se nos piden por parámetro.
deleteCharAt(int index), que borrar el carácter que ocupa la posición que se especifica por parámetro.
reverse(), da la vuelta completa al contenido.
java.text
El paquete java.text contiene clases e interfaces para manejar textos, fechas y números, de forma independiente al idioma en el que sea utilizada la aplicación, lo que nos permitirá independizarnos de los formatos de visualización diferentes por país y trabajar de una forma común desde el programa.
El cometido de un formateador es conseguir a partir de un número la visualización que queramos en función del contenido que estemos manipulando, y para conseguir este formato que deseamos utilizaremos el método format:
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
double d = 123.57;
System.out.println(nf.format(d));
En el ejemplo hemos obtenido una instancia de la clase NumberFormat a partir de uno de sus métodos estáticos definidos a este fin, y hemos indicado que el formato del número de salida lo queremos para la región alemana, que en vez de puntos para separar los decimales utiliza la coma. Si revisamos la salida de nuestro programa veremos:
123,57
java.text.NumberFormat
La clase java.text.NumberFormat es una clase abstracta y padre de las que permiten formatear números. Esta clase contiene métodos estáticos para obtener el formateador apropiado en base al tipo de número que se quiera formatear. Por ejemplo, si queremos formatear una moneda, utilizaremos el método estático getCurrencyInstance. Como el formateo de monedas varía en función del idioma y la cultura del usuario que trabaja con el programa, puedes especificar la región del usuario. Utilizaremos la clase java.util.Locale con este fin.
El cometido de un formateador es conseguir a partir de un número la visualización que queramos en función del contenido que estemos manipulando, y para conseguir este formato que deseamos utilizaremos el método format:
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
double d = 123.57;
System.out.println(nf.format(d));
En el ejemplo hemos obtenido una instancia de la clase NumberFormat a partir de uno de sus métodos estáticos definidos a este fin, y hemos indicado que el formato del número de salida lo queremos para la región alemana, que en vez de puntos para separar los decimales utiliza la coma. Si revisamos la salida de nuestro programa veremos:
123,57
Donde el separador lo ha modificado el formateador. Aunque podíamos haber utilizado el formateador con otro fin totalmente distinto, como mostrar un percentil, como mostramos en el siguiente ejemplo:
NumberFormat pf = NumberFormat.getPercentInstance();
double p = 0.47;
System.out.println(pf.format(p));
Cuyo resultado de salida por consola, es totalmente distinto al anterior:
47%
DecimalFormat
La clase DecimalFormat deriva de la clase que acabamos de ver y dispone de gran variedad de posibilidades para formatear números decimales, incluso indicar la precisión que se quiere utilizar, ceros, sufijos y prefijos. Es posible obtener una instancia de esta clase de dos formas diferentes:
- Utilizando uno de los constructores que dispone la clase, que es muy útil cuando queremos trabajar con el Locale por defecto.
- Pero cuando queremos utilizar un Locale, deberemos invocar a uno de los métodos estáticos de la clase NumberFormat y hacer un cast de la instancia devuelta a la clase DecimalFormat.
Un objeto DecimalFormat tiene un patrón que representa el formato de un número decimal. El patrón se crea a partir de varios símbolos que incluyen los puntos, las almohadillas, y los ceros, que registraran los comodines.
En el siguiente ejemplo se muestra como crear un patrón con DecilmalFormat y cual es su resultado.
double d = 1234567.437;
DecimalFormat one = new DecimalFormat(“###,###,###.###”);
System.out.println(one.format(d));
DecimalFormat two = new DecimalFormat(“000,000,000.00000”);
System.out.println(two.format(d));
DecimalFormat three = new DecimalFormat(“$#,###,###.##”);
System.out.println(three.format(d));
A continuación se muestran los tres resultados que son parecidos, aunque tienen diferencias que les hemos otorgado gracias al patrón utilizado.
1,234,567.437
001,234,567.43700
$1,234,567.44
Tanto java.text.NumberFormat como DecimalFormat cuentan con un método parse que permite realizar la operación de forma inversa, a partir de una cadena es posible generar un número decimal especificando el patrón en que se proporciona la cadena y a partir del cual se construirá el número.
En el siguiente ejemplo mostramos este caso:
NumberFormat en = NumberFormat.getInstance(Locale.US);
NumberFormat fr = NumberFormat.getInstance(Locale.FRANCE);
try {
String s = “123,45”;
System.out.println(en.parse(s));
System.out.println(fr.parse(s));
} catch(ParseException e) {
e.printStackTrace();
}
Aunque en la codificación el separador decimal es el punto en este ejemplo hemos construido un número a partir de una cadena con un separador coma, gracias a la clase NumberFormat y su método parse.
La clase java.text.DateFormat
La clase java.text.DateFormat es abstracta y es capaz de formatear y parsear fechas y horas para un Locale especifico. Es posible crear una clase de este tipo para trabajar sólo con fechas, o con fecha y hora. A continuación se muestran diferentes formas de crear esta clase:
-
public static final DateFormat getDateInstance(), obtiene un objeto que sirve para trabajar con fechas con un Locale por defecto.
-
public static final DateFormat getDateInstance(int style, Locale loc), obtiene un formateador preparado para trabajar con tipo especifíco de fechas y un Locale. En el parámetro style es posible pasarle diferentes valores que son: FULL, LONG, MEDIUM y SHORT, que son constantes predefinidas en la clase DateFormat y que cada una contiene un formato específico de fecha.
-
public static final DateFormat getTimeInstance(), obtiene un objeto que sirve para formatear fechas y horas en el Locale por defecto.
-
public static final DateFormat getTimeInstance(int dateStyle, int timeStyle, Locale loc), obtiene un objeto para formatear fechas y horas con un formato de fecha específico, uno de hora específico y para un Locale concreto.
DateFormat define una tercera versión de estos métodos donde se debe proporcionar el estilo con el parámetro entero de entrada, pero no se pasa el Locale, por lo cual funciona con los anteriores pero para un Locale por defecto.
Esta clase define tres métodos format, aunque realmente sólo hace falta conocer uno: public final String format(java.util.Date date).
La clase java.util.Date es una clase muy útil y con la que se trabaja mucho en Java, que representa un instante específico en milisegundos. El método format lo que hace es devolver una representación en formato cadena de esta fecha que pasamos como argumento.
Veamos el siguiente ejemplo de uso de esta clase:
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
DateFormat full =DateFormat.getDateInstance(DateFormat.FULL);
Date fecha = new Date(1300000000000L);
System.out.println(df.format(fecha));
System.out.println(full.format(fecha));
Donde se obtiene el siguiente resultado en base al código ejecutado:
13/03/11domingo 13 de marzo de 2011
Vemos que aunque trabajamos con la misma fecha, gracias al formateador obtenemos diferentes representaciones de nuestra fecha en función de cómo lo hayamos configurado.
Al igual que NumberFormat, en esta clase contamos con un método parse que realiza la operación inversa a la que acabamos de estudiar. Este método es capaz de a partir de una cadena obtener una fecha, este método puede lanzar una ParseException si la cadena que se pasa como parámetro no cumple con el formato.
DateFormat shortFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
String s = "01/03/2011";
try {
Date date = shortFormat.parse(s);
DateFormat fullFormat = DateFormat.getDateInstance(
DateFormat.FULL,
Locale.FRANCE);
System.out.println(fullFormat.format(date));
}catch(ParseException e) {
e.printStackTrace();
}
Como resultado de este último ejemplo que hemos programado obtenemos:
lundi 3 janvier 2011
Operaciones con expresiones regulares en JAVA
Una expresión regular es una secuencia de caracteres que describe un patrón. El patrón describe una serie de cadenas basadas en unas características comunes. La sintaxis de estas expresiones regulares no es única de Java, y se utilizan en muchos otros lenguajes de programación diferentes. Java cuenta con las clases Pattern y Matcher que se encuentran en el paquete java.util.regex y permiten realizar operaciones con las expresiones regulares.
Para trabajar con estas expresiones es necesario reconocerlas y saber construirlas (limitadas a los siguientes caracteres: . (punto), * (asterisco), + (suma), ¿, \d, \s, \w, [], () ). Vamos a identificar un conjunto de clases muy útiles que encontramos dentro del API de JAVA que permiten trabajar con expresiones regulares.
Uso de las clases Pattern y Matcher en JAVA
Comencemos con un ejemplo:
String regex = "hola";
Pattern pattern = Pattern.compile(regex);
Matcher m1 = pattern.matcher("hola");
Matcher m2 = pattern.matcher("adios");
if(m1.matches()) {
System.out.println("hola es un resultado");
}
if(m2.matches()) {
System.out.println("adios es un resultado");
}
Pattern representa la compilación de una expresión regular. No necesitaremos, como se puede ver, instanciar un objeto de la clase Pattern, las instancias son obtenidas a partir de invocar al método estático compile.
Las expresiones regulares, necesariamente se deben compilar en un patrón. El resultado de la compilación (objeto de tipo Pattern) se le pasará a una instancia de Matcher que guarda la cadena donde queremos realizar la búsqueda y con el método matches no dirá si ha obtenido algún resultado.
Normalmente las expresiones regulares se hacen más complejas que la que hemos visto en el ejemplo. Para construirlas es posible utilizar un juego especial de caracteres para especificar comodines, repeticiones, rangos y demás.
Veamos varios ejemplos de expresiones regulares con estos caracteres especiales y su comportamiento:
String regex = ".endo";
Pattern patron = Pattern.compile(regex);
String [] pruebas = {"endo", "vendo", "corriendo", "tejiendo"};
for(String prueba: pruebas) {
Matcher m = patron.matcher(prueba);
if(m.matches()) {
System.out.println(prueba + " concuerda con el patron " + regex);
}
}
El punto en una expresión regular indica que buscamos una cadena donde en la posición que ocupa el punto puede haber cualquier letra. Por lo tanto la salida de esta ejecución es:
vendo concuerda con el patron .endo
Si en cambio queremos indicar que no sea una palabra exactamente de cuatro letras, deberemos utilizar el . en combinación con el *, que indica que la terminación endo puede ir precedida de cualquier letra y cualquier cantidad.
Veamos el ejemplo con el cambio:
String regex = ".*endo";
Pattern patron = Pattern.compile(regex);
String [] pruebas = {"endo", "vendo", "corriendo", "tejiendo"};
for(String prueba: pruebas) {
Matcher m = patron.matcher(prueba);
if(m.matches()) {
System.out.println(prueba + " concuerda con el patron " + regex);
}
}
Y en cambio la salida es totalmente distinta:
endo concuerda con el patron .*endo
vendo concuerda con el patron .*endo
corriendo concuerda con el patron .*endo
tejiendo concuerda con el patron .*endo
Podemos apoyarnos en los corchetes para indicar que entre todos los resultados que hemos obtenido solo nos devuelva los que la composición de la parte variable esté compuesta únicamente de determinados caracteres.
String regex = "[vteji].*endo";
Pattern patron = Pattern.compile(regex);
String [] pruebas = {"endo", "vendo", "corriendo", "tejiendo"};
for(String prueba: pruebas) {
Matcher m = patron.matcher(prueba);if(m.matches()) {
System.out.println(prueba + " concuerda con el patron " + regex);
}
}
Con este nuevo cambio el resultado del programa es:
vendo concuerda con el patron [vteji].*endo
tejiendo concuerda con el patron [vteji].*endo
La clase Pattern en JAVA
Para la clase Pattern se puede utilizar conjuntos de caracteres que representan a los patrones que se utilizan más comúnmente. Y estos son los que se deben conocer:
-
\d que denota un digito equivalente a [0-9]
-
\s que denota un espacio en blanco equivalente a [ \t\n\x0B\f\r]
-
\w que denota una letra equivalente a [a-zA-Z_0-9]
Debido al comienzo con la barra invertida en Java debemos escapar estas secuencias con una barra invertida adicional. Por ejemplo la próxima expresión regular busca uno o más dígitos:
String digits = “\\d+”;
Se obtienen los siguientes resultados:
John Doe coincide con el patron [A-Z]\w*\s+[A-Z]\w+
John Doe coincide con el patron [A-Z]\w*\s+[A-Z]\w+
J D5 coincide con el patron [A-Z]\w*\s+[A-Z]\w+
Como hemos podido apreciar puede que las expresiones regulares sean un poco complicadas al principio, pero realmente son una herramienta muy potente para encontrar cadenas.
String s = "[A-Z]\\w*\\s+[A-Z]\\w+";
Patterm x = Pattern.compile(s);
String [] names = {"John Doe", "JohnDoe","John\tDoe", "John doe", "J D", "J D5"};
for (String name: names) {
Matcher m = x.matcher(name);
if (m.matches()) {
System.out.println(name + "coincide con el patron" +s );
}
}
Seguimos con el curso de Java en el siguiente enlace:
Programación en Java SE 6 desde cero: Parte 4
Las dudas que os puedan comentarlas justo aquí debajo e iremos respondiendo. ¡Deja un comentario!