form_valida.js: validação da entrada de dados em um formulário

Em alguns formulários, podem existir campos que precisam ser informados em uma formato específico, como por exemplo data e hora, alguns tipos de código de produto, ou identificadores como CPF e CNPJ.

Esses padrões de entrada de dados podem ser gerados com expressões regulares. Nesse artigo, veremos como usar expressões regulares para forçar que um campo receba os dados no formato correto, além de exibir neste campo um modelo visual do formato.
Aqui, usaremos a função .on() do jQuery para tratar dois eventos relacionados a cada campo de um formulário: focus e keypress. O evento focus é disparado quando campo recebe o foco, e keypress é disparado quando uma tecla é pressionada enquanto o campo está em foco.
Para saber quais campos devem ser validados, devemos definir para cada um um atributo class com um valor comum, e também adicionar o atributo pattern, com a expressão regular que define o padrão de entrada de dados.
As funções para esses eventos tem a seguinte estrutura:

$(document).on('focus', '.valida', function(e) {
...
}
$(document).on('keypress', '.valida', function(e) {
}

Na função do evento focus, iremos gerar uma string com um modelo de entrada de dados, de acordo com o padrão do campo. Essa string será mostrada no campo e será atualizada a medida que um caractere for digitado. Na função keypress, o script lê o caractere que foi pressionado, checa corresponde ao tipo esperado para a posição atual, e caso seja, atualiza a string com esse caractere.
Abaixo temos a função focus, que apenas inicializa as variáveis e gera uma string que será mostrada no campo:

$(document).on('focus', '.valida', function(e) {
 regex = $(this).attr('pattern');
 counter = 0;
 tam = size_of(regex);
 str = generate_string(regex, tam);
 $(this).val(str);
});

Nesta função, é usada a função auxiliar generate_string(), mostrada a seguir:

function generate_string(regex, tamanho) {
 var str = '';
 for(var i=0; i<tamanho; i++) {
 var type = type_of(regex, i);
 if(type == 'number' || type == 'string')
 str = str + '_';
 else
 str = str + type;
 }
 return str;
}

Na função keypress, a cada tecla pressionada, o script checa qual o tipo esperado para a posição atual, e se for a mesma do caractere digitado, atualiza a string que é exibida no campo:

$(document).on('keypress', '.valida', function(e) {
 e.preventDefault();
 //var tecla = e.which;
 var tecla = (e.which) ? e.which : e.keyCode;
 var tecla2;
 if(tecla >= 48 && tecla <= 57)
 tecla2 = tecla - 48;
 else
 tecla2 = String.fromCharCode(tecla);
 var t = type_of(regex, counter);
 if(counter < tam) {
 if(t != 'number' && t != 'string') {
 str = replaceAt(str, counter, t);
 counter++;
 }
 t = type_of(regex, counter);
 if(typeof tecla2 == t) {
 str = replaceAt(str, counter, tecla2);
 counter++;
 }
 }
 $(this).val(str);
});

Aqui, usamos a função auxiliar replaceAt(), que substitui um caractere da string que é exibida pelo caractere digitado:

function replaceAt(s, n, t) {
 return s.substring(0, n) + t + s.substring(n + 1);
}

Outras funções auxiliares usadas são:
size_of – calcula o tamanho de uma string dada a sua expressão regular correspondente

function size_of(regex) {
 var parsedRegexp = parse(regex);
 return parsedRegexp.length;
}

type_of – retorna o tipo de caractere em uma posição da string dada a sua expressão regular

function type_of(regex, posicao) {
 var parsedRegexp = parse(regex);
 var pos = parsedRegexp[posicao];
 if(pos == '0-9')
 return 'number';
 if(pos == 'A-Z' || pos == 'a-z')
 return 'string';
 return pos;
}

parse – processa a expressão regular passada como parâmetro e retorna um vetor onde cada elemento é uma sub-expressão que informa qual o tipo de caractere é esperado nesta posição.

function parse(regexString){
 var regex = /((?!\[|\{).(?!\]|\}))|(?:\[([^\]]+)\]\{(\d+)\})/g,
 match,
 model = [];
 while (match = regex.exec(regexString)) {
 if(typeof match[1] == 'undefined'){
 for(var i=0;i<match[3];i++){
 model.push(match[2]);
 }
 }else{
 model.push(match[1]);
 }
 }
 return model;
}