Ir al contenido principal

Expresiones Regulares y pruebas en javascript

¿Qué es una expresión regular?
Una expresión regular es una cadena que contiene una combinación de caracteres normales y metacaracteres o metasecuencias especiales. Los caracteres normales coinciden por ellos mismos. Los metacaracteres y metasecuencias son caracteres o secuencias de caracteres que representan ideas como cantidad, posiciones o tipos de caracteres.
Regular Expression Pocket Reference 2nd Ed - Tony Stubblebine - O'Reilly

¿Para qué son útiles las expresiones regulares?
Las expresiones son especialmente útiles para validar información, por ejemplo en formularios de ingreso de datos. Por ejemplo para validar que se ingresó un número de teléfono, puedes usar la siguiente expresión regular.

/^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})?$/

Parecieran símbolos al azar, pero nada mas lejos de la realidad. Te muestro una tabla básica con los elementos usados para crear expresiones regulares.

Carácter Texto buscado
^ Principio de entrada o línea.
$ Fin de entrada o línea.
* El carácter anterior 0 o más veces.
+ El carácter anterior 1 o más veces.
? El carácter anterior una vez como máximo (es decir, indica que el carácter anterior es opcional).
. Cualquier carácter individual, salvo el de salto de línea.
x|y x o y.
{n} Exactamente n apariciones del carácter anterior.
{n,m} Como mínimo n y como máximo m apariciones del carácter anterior.
[abc] Cualquiera de los caracteres entre corchetes. Especifique un rango de caracteres con un guión (por ejemplo, [a-f] es equivalente a [abcdef]).
[^abc] Cualquier carácter que no esté entre corchetes. Especifique un rango de caracteres con un guión (por ejemplo, [^a-f] es equivalente a [^abcdef]).
\b Límite de palabra (como un espacio o un retorno de carro).
\B Cualquiera que no sea un límite de palabra.
\d Cualquier carácter de dígito. Equivalente a [0-9].
\D Cualquier carácter que no sea de dígito. Equivalente a [^0-9].
\f Salto de página.
\n Salto de línea.
\r Retorno de carro.
\s Cualquier carácter individual de espacio en blanco (espacios, tabulaciones, saltos de página o saltos de línea).
\S Cualquier carácter individual que no sea un espacio en blanco.
\t Tabulación.
\w Cualquier carácter alfanumérico, incluido el de subrayado. Equivalente a [A-Za-z0-9_].
\W Cualquier carácter que no sea alfanumérico. Equivalente a [^A-Za-z0-9_].
Mas información: http://www.regular-expressions.info/reference.html

Caso de ejemplo

Creemos una expresión regular para validar nombres de usuario, con las siguientes reglas:
  1. 1. Puede contener letras, números y los siguientes caracteres: ( _ guión bajo), ( . punto), ( - guión)
  2. 2. Debe iniciar con un caracter alfanumérico o ( _ guión bajo)
  3. 3. La cadena debe contener al menos una letra o número

Teniendo claro las reglas procederemos con la regla que me parece mas fácil, la número dos, así tendremos:

/^[\w]{1}$/

/^ simplemente nos indica el inicio de la expresión 
\w Cualquier caracter alfanumérico
{1}  Limita la expresión enterior a repetirse una sola vez exactamente
$/  Fin de la expresión
  

Esa expresión tal y como está nos restringe a una palabra con un solo caracter, pero si la combinamos con mas expresiones se convierte en un validador del primer caracter. Ahora tomemos la regla número 1, que también es fácil

/^[\w]{1}[0-9a-zA-Z_|\-|\.]$/
 
[0-9a-zA-Z_|\-|\.]  Esto es lo único que agregamos con respecto al anterior y lo veremos en detalle:
  [] no dice que será un grupo, 0-9 representa una secuencia en este caso todos los números entre 0 y 9 incluyendolos, a-z y A-Z  es análogo, \- es el caracter (- guión) que debe ser escapado por que un guión solitario tiene otro rol dentro de las expresiones regulares, igual con \.

Así que tenemos validado que nuestro primer caracter sea alfanumérico y que a continuación siga cualquier cantidad de caracteres alfanuméricos o los tres caracteres especificados en la regla. Sin embargo esta validación aun permite cadenas como _------- ó _.......... que claramente no son aceptables. Así llegamos a la última regla y para mí la mas complicada de realizar.

/^\w{1}([0-9a-zA-Z_|\-|\.]*[0-9a-zA-Z]+[0-9a-zA-Z_|\-|\.]*)$/
 
La idea que apliqué fue dividir la cadena después del primer caracter en tres partes:
[0-9a-zA-Z_|\-|\.]*  Esto nos dice lo mismo que en el paso dos excepto que el asterisco la hace una parte opcional es decir que se puede repetir 0 o muchas veces
 [0-9a-zA-Z]+  Parecido al anterior, excepto que no permite los caracteres _, -, ., y el + final nos dice que se debe repetir 1 o mas veces, haciendolo obligatorio
[0-9a-zA-Z_|\-|\.]* Igual que el primero 
  
Y con esto nos aseguramos la tercer regla.

Intuimos que funcionará pero no tenemos la certeza así que aplicaremos unas pruebas en javascript:

var test= {
    expresion : new RegExp(/^\w{1}([0-9a-zA-Z_|\-|\.]*[0-9a-zA-Z]+[0-9a-zA-Z_|\-|\.]*)$/),
    init: function(){
        var debenPasar = ['juan','_juan','juan_',
            'juan.carlos','juan_carlos','juan-carlos'];
        var noDebenPasar = ['-juan','.juan','------','_____','.....','_-----','_....','a_____','a......'];
        this.probar(debenPasar, true);
        this.probar(noDebenPasar, false);
    },
    probar : function(datos, resultado){
        for(var i=0; i<datos.length; i++){
            if(this.expresion.test(datos[i])!=resultado){
                console.log(datos[i]+' rompe la regla');
                return false;
            }
        }
        return true
    }
};
test.init();


Si tienen un caso que rompa la expresión regular, favor dejarla en los comentarios

Comentarios

  1. Hola, me parecio muy interesante el articulo. Estaba buscando precisamente esta validación y me sirvió de mucho. Felicidades y sigue adelante.
    Saludos

    ResponderEliminar
  2. Este comentario ha sido eliminado por el autor.

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Enumerar filas en una consulta con MySQL

Supongamos que tenemos tablas con la estructura siguiente: documentos (iddocumento, nombre_documento, url_original, idtipo_documento, idproyecto) proyectos (idproyecto, nombre_proyecto, longitud, unidad_medida) tipo_documentos (idtipo_documento, descripcion_tipo_documento) Tenemos necesidad de hacer una consulta como la siguiente: "Enumerar todos los documentos en la base de datos agrupados por proyecto" Parece fácil, excepto por el término "enumerar", aquí tienes un truquito para que logres enumerar tus consultas: SELECT (@rownum:=@rownum+1) AS rownum, nombre_documento, descripcion_tipo_documento, nombre_proyecto FROM (SELECT @rownum:=0) r, documentos AS d INNER JOIN proyectos AS p ON d.idproyecto = p.idproyecto INNER JOIN tipo_documentos AS td ON d.idtipo_documento = td.idtipo_documento Pero que tal si te piden que enumeres los proyectos con sus correspondientes documentos?. Teniendo lo anterior es un poco mas sencillo SELECT IF(@fila=proyectos.idproyecto, ...

jQuery DataTables y CodeIgniter

Ajax Source Datatables permite configurar fácilmente el origen de datos de la tabla, para que esta sea generada dinámicamente desde el servidor, así que con CodeIgniter tendríamos el siguiente código public function page(){ $data['pedidos'] = $this->pedidos_model->get_pedidos($this->input->post('iDisplayStart')); define('AJAX_REQUEST', 1);//truco para que en nginx no muestre el debug $TOTAL = $this->pedidos_model->total(); echo json_encode(array('aaData'=>$data['pedidos'], 'iTotalRecords'=>$TOTAL, 'iTotalDisplayRecords'=>$TOTAL, 'sEcho'=>$this->input->post('sEcho'))); } Este método producirá algo parecido a esto: {"iTotalRecords":83099,"iTotalDisplayRecords":83099,"sEcho":"2", "aaData":[{"Id":"85514","num":"86109...