Validando datas com JavaScript e Expressões Regulares


Expressões Regulares, conhecidas também como regex, são muito úteis na área de programação. Uma das utilidades das ERs é a validação de dados.

Estava estudando ERs e, para treinar, decidi fazer um sistema de validação de datas em JavaScript, algo bastante útil, embora já existam funções prontas que fazem isso, como no jQuery, talvez no futuro eu cite algumas dessas funções.

Validar datas com ERs é útil porque elas são aceitas em várias linguagens diferentes, assim o seu script em PHP (ou outra linguagem de servidor) pode validar novamente os dados, por segurança, usando a mesma ER. Você não precisará se dar ao trabalho de escrever um novo código.

Existem duas maneiras de se definir uma ER em JavaScript:

var regex = /regex/;
//ou
var regex = new RegExp ("regex");

Sempre tomando cuidado para escapar os caracteres corretamente.

Validando Datas

Vamos ao que interessa. Em primeiro lugar vamos definir uma ER genérica, depois vamos melhorando-a até chegar naquilo que queremos (preste atenção no escape do caractere ‘/‘).

var regex = /..\/..\/..../;

Isso reconhece qualquer coisa, como “e3/34/e %[“, e isso não é o que queremos. Vamos limitar apenas a números (\d). Além disso, a data deve ser a única coisa no campo, então vamos dizer que é no começo da linha (^) e que também é no final da linha ($).

var regex = /^\d\d\/\d\d\/\d\d\d\d$/;

Ok. Mas isso aceitaria algo como “43/56/9999″, temos que limitar o dia até 31 e o mês até 12. E nenhum dos dois pode ser “00″. Então o dia deve ser 0 e um número entre 1 e 9, 1 ou 2 e um número ou 3 e 0 ou 1. Algo parecido para o mês. O ano deve ser entre 1900 e 2099. Vamos agrupar cada pedaço, para ficar mais fácil (ou não).

var regex = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/((19|20)\d\d)$/;

Bom, o dia pode possuir apenas um dígito se estiver entre 1 e 9. O mesmo vale para o mês. O ano também pode ser no formato reduzido de apenas dois dígitos. Vamos deixar algumas coisas opcionais (?).

var regex = /^(0?[1-9]|[12][0-9]|3[01])\/(0?[1-9]|1[0-2])\/((19|20)?\d\d)$/;

Está ficando bonito, não é? Agora vem o problema. Uma data do tipo “31/4/09″ é válida, mas abril não tem dia 31. Teremos que dividir por mês, permitindo a quantidade de dias apropriada. Existem basicamente dois jeitos de se fazer isso. O primeiro é mantendo o intervalo de dias inteiro para cada tipo de mês (29, 30 ou 31 dias). Outro modo seria permitir 28 dias para todos os meses, 29 e 30 para todos menos fevereiro e 31 para os meses de 31 dias. Vou usar essa segunda maneira, porque deixa a ER menor e mais fácil de entender (às vezes uma maior é mais fácil de entender, nesse caso deixe ela maior). O agrupamento é importante, pois o operador OU (|) é o último da lista de precedência.

var regex = /^(((0?[1-9]|1\d|2[0-8])\/(0?[1-9]|1[0-2]))|
 //28 para todos os meses
((29|30)\/(0?[13456789]|1[0-2]))|
 //29 e 30 para todos menos fevereiro
(31\/(0?[13578]|1[02])))
 //31 para jan, mar, mai, jul, ago, out e dez
\/((19|20)?\d\d)$/;

Lembre-se que ERs em JavaScript não aceitam comentários e muito menos quebras de linha,eu só fiz isso para explicar as partes da ER. Se achar que precisará comentar, use o outro formato de definição, quebrando a string passada ao RegExp (nesse caso, lembre-se que a barra inversa ‘\’ precisa ser escapada ‘\\’). Nossa ER está quase pronta. O único defeito é que ela não aceita o dia 29 de fevereiro, o que é válido nos anos bissextos. Não podemos deixá-la aceitar o dia 29/2 em todos os anos, então vamos deixar ela do jeito que está e apenas acrescentar uma condição.

Mas essa condição não é exatamente simples. Um ano é bissexto se for divisível por 4. Se termina com 00, o ano é bissexto se for divisível por 400. 2000 é ano bissexto, mas 1900 não é. Um número é divisível por quatro se o número formado pelos dois últimos dígitos for divisível por quatro. Isso só é possível de se fazer com ER porque a tabuada do 4 segue um padrão peculiar. Dos dois dígitos, se o primeiro for par (0 é par) então o segundo deve ser 0, 4 ou 8 e se o primeiro algarismo for ímpar o segundo deve ser 2 ou 6. Com ER, isso ficaria assim:

var regex = /\b\d*(([02468])[048])|([13579][26])\b/;

Essa é uma ER que casa com qualquer número múltiplo de 4 (de pelo menos dois dígitos). Vamos aplicar o mesmo conceito à nossa ER de validação, lembrando que 1900 é divisível por 4, mas não é bissexto e que 00 é equivalente ao ano 2000.

var regex = /^((((0?[1-9]|1\d|2[0-8])\/(0?[1-9]|1[0-2]))|
 //28 para todos os meses
((29|30)\/(0?[13456789]|1[0-2]))|
 //29 e 30 para todos menos fevereiro
(31\/(0?[13578]|1[02])))
 //31 para jan, mar, mai, jul, ago, out e dez
\/((19|20)?\d\d))$|
((29\/0?2\/)
 //29 de fevereiro
((19|20)?(0[48]|[2468][048]|[13579][26])|(20)?00))$/;

E, finalmente, nossa ER está pronta. Só falta aplicá-la num código de validação:

function valida_data(element) {
 regex = /^((((0?[1-9]|1\d|2[0-8])\/(0?[1-9]|1[0-2]))|((29|30)\/
        (0?[13456789]|1[0-2]))|(31\/(0?[13578]|1[02])))\/((19|20)?\d\d))$|
        ((29\/0?2\/)((19|20)?(0[48]|[2468][048]|[13579][26])|(20)?00))$/;
 
 resultado = regex.exec(element.value);
 if(!resultado) {
   fica_errado(element);
 }
 else {
   fica_certo(element);
 }
}//fim da função

Sendo que fica_certo() e fica_errado() são funções que avisam o usuário de que a data está válida ou inválida, respectivamente. Essa função pode ser usada no evento onkeyup de um input type=text, por exemplo:

<input onkeyup="valida_data(this);" type="text" />

E pronto! Se quiser, veja um exemplo aqui. Como ERs podem ser aplicadas em várias linguagens de programação, você pode reaproveitá-la, provavelmente mudando apenas os escapes de caracteres. Fica aí a dica.

    

Uma resposta para “Validando datas com JavaScript e Expressões Regulares”

  1. Pa3cK disse:

    Muito útil =D

Deixe uma resposta