jueves, 19 de abril de 2012

Validable JTextField, espresiones regulares en Java

1 comentarios
Hola compañeros, en la mayoría de los formularios de nuestras aplicaciones nos vemos en la necesidad de validar las entradas del usuario.

Esto en primer lugar puede parecer una tarea tediosa, sin embargo, vamos a ver como realizarla de una manera fácil.

Expresiones regulares en Java

Para ello nos valdremos del uso de expresiones regulares. Las expresiones regulares son una manera de describir un conjunto de cadenas de texto que comparten características comunes. Se pueden usar para buscar, editar o manipular textos.
El soporte para las expresiones regulares en java lo proporciona la API java.util.regex.
Las clases principales de este paquete que vamos a utilizar son la clase Pattern y la clase Matcher.

La clase Pattern proporciona una versión compilada de una expresión regular, no tiene constructor público por lo que para usarlo deberemos invocar a uno de sus métodos estáticos compile.
Un objeto Matcher se encarga de interpretar el patrón y realiza operaciones buscando coincidencias en una cadena introducida. Al igual que la clase Pattern, no dispone de constructores públicos por lo que para obtener una instancia invocaremos al método matcher en un objeto Pattern.

Un ejemplo del uso básico de estas clases lo presentamos a continuación, las utilizaremos para buscar cadenas que sean exactamente “a”, “b” o “c”.
String regEx = "[abc]";
  Pattern pattern = Pattern.compile(regEx);
  Matcher matcher = pattern.matcher("a");
  if (matcher.matches()) {
   System.out.println("Se encontró la cadena buscada");
  }

Siguiendo con el tema de los formularios en Swing, podemos utilizar expresiones de este tipo para crear un componente de texto que valide la entrada.
Para ello crearemos una clase que hereda de JTextField y que nos permite pasar una expresión regular al constructor para validar la entrada cada vez que se pulse una tecla. Nuestro componente quedaría así:

package validableJTextfield;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.BorderFactory;
import javax.swing.JTextField;
import javax.swing.border.Border;

public class ValidableTextField extends JTextField {

 private Pattern pattern;

 private Border wrongBorder = BorderFactory.createLineBorder(Color.RED);
 private Border defaultBorder;

 /**
  * Constructor.
  * @param regEx Expresión regular para evaluar
  */
 public ValidableTextField(String regEx) {
  super();
  this.defaultBorder = this.getBorder();
  this.setColumns(15);
  this.pattern = Pattern.compile(regEx);
  this.addKeyListener(new KeyListener() {

   @Override
   public void keyTyped(KeyEvent e) { }

   @Override
   public void keyReleased(KeyEvent e) {
    validateText();
   }

   @Override
   public void keyPressed(KeyEvent e) { }
  });
 }

 private void validateText() {
  Matcher matcher = pattern.matcher(this.getText());
  if (!matcher.matches()) {
   this.setBorder(wrongBorder);
  } else {
   this.setBorder(defaultBorder);
  }
 }

}

Os dejo un ejemplo de la construcción de las expresiones regulares más comunes:

[abc]                     “a”, “b”, o “c” (simple)
[^abc]                   Cualquier carácter excepto “a”, “b”, o “c” (negación)
[a-zA-Z]               De la “a” a la “z”, o de la “A” a la “Z”, ambas inclusive(rango)
[a-d[m-p]]            De la “a” a la “d”, o de la “m” a la “p”: [a-dm-p] (union)
[a-z&&[def]]        “d”, “e”, o “f” (intersección)
[a-z&&[^bc]]       “a” a la “z”, excepto “b” y “c”: [ad-z] (resta)
[a-z&&[^m-p]]     “a” a la “z”, pero no de la “m” a la “p”: [a-lq-z] (resta)

Y algunos atajos.
.                            Cualquier carácter.
\d                          Un dígito: [0-9]
\D                         Dígitos no: [^0-9]
\s                          Un espacio en blanco: [ \t\n\x0B\f\r]
\S                         Cualquiera excepto un espacio en blanco: [^\s]
\w                         Un carácter alfanumérico: [a-zA-Z_0-9]
\W                        Un carácter no de palabra: [^\w]

Veamos algunos ejemplos del uso de estar expresiones en nuestro componente, crearemos 4 ValidableTextField y le asignaremos a cada uno una expresión regular distinta para obtener algo como esto:


package validableJTextfield;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class Main {

 private static void createAndShowGUI() {
  JFrame frame = new JFrame("Validable JTextField");

  JPanel container = new JPanel();

  JLabel labelLetters = new JLabel("Solo letras");
  ValidableTextField textFieldLetters = new ValidableTextField("[a-zA-Z]*");

  JLabel labelNumbers = new JLabel("Solo números");
  ValidableTextField textFieldNumbers = new ValidableTextField("[0-9]*");

  JLabel labelLetters3 = new JLabel("Tres caracteres alfanuméricos");
  ValidableTextField textFieldLetters3 = new ValidableTextField("[a-zA-Z0-9]{3}");

  JLabel labelLetters35 = new JLabel("Entre 3 y 5 caracteres alfanuméricos");
  ValidableTextField textFieldLetters35 = new ValidableTextField("[a-zA-Z0-9]{3,5}");

  container.add(labelLetters);
  container.add(textFieldLetters);

  container.add(labelNumbers);
  container.add(textFieldNumbers);

  container.add(labelLetters3);
  container.add(textFieldLetters3);

  container.add(labelLetters35);
  container.add(textFieldLetters35);

     frame.getContentPane().add(container);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setSize(225, 250);
     frame.setVisible(true);
 }

 public static void main(String[] args) {

  javax.swing.SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    createAndShowGUI();
   }
  });
 }
}

Y eso es todo por hoy si os han quedado cuestiones sin resolver sobre este tema, no dudéis en utilizar la página de Consultas ¿Necesitas ayuda con tu código? Para poneros en contacto conmigo.