segunda-feira, 29 de dezembro de 2014

Regex para validação de moeda

Olá amigos leitores. O tema do post dessa semana foi escolhido por uma necessidade que tive muito tempo atrás. Quando me deparei com o problema aplicar máscaras monetárias (R$) em campos de texto, resolvi construir uma solução própria. Poderia ter usado soluções prontas ? Sim, poderia mas, eu não queria ficar amarrado à soluções de terceiros.

Para resolver o problema, não queria criar uma função grande e de complexidade elevada sendo que, uma regex poderia lidar com esse problema. Então, vamos lá !!

A regex construída:

 ^R\$(\d{1,3}(\.\d{3})*|\d+)(\,\d{2})?$  

Esta regex aceita estes valores:
  • R$2,00
  • R$20,00
  • R$2.000,00
  • R$20.000,00
  • R$200.000,00
  • R$2.000.000,00
Mas, não aceita esses:
  • 2,00
  • 2
  • R$aaa44,00
  • B$20,00
  • $100,00
Importante: Note que o caracter usado para separar os reais dos centavos é o vírgula (,) e não o ponto (.).

Agora, vamos às partes das explicações. Vamos destrinchar a regex.

Os caracteres ^ e $, respectivamente, no início e fim da expressão regular denotam um intervalo fechado, ou seja, o texto que for avaliado só pode conter o dado monetário.

O caracter representa o próprio R do R$. Então, até aí, nenhum mistério. O $ possui significado especial nas regex, logo precisamos de uma barra de escape (\$) para que ela adote a representação de cifrão ($).

Com (\d{1,3}(\.\d{3})*|\d+) definimos que teremos ou algo desse tipo: 2.000 ou 2000. Vamos melhorar isso.

\d{1,3} -> \d representa um dígito. O {1,3} representa no mínimo 1 e no máximo 3 ocorrências. Então, quando temos \d{1,3} estamos querendo dizer que, teremos um dígito que terá no mínimo 1 e no máximo 3 ocorrências.
(....) -> Os parênteses () são usados para definir um subconjunto.
\. -> A barra de escape é usada no ponto (.) para definir o separador de milhar.
\d{3} -> Representa um dígito que será repetido três vezes.
* -> Representa que algo será repetido 0 ou infinitas vezes.
| -> Representa uma operação de ou.
\d+ -> Representa que um dígito será repetido no mínimo 1 e no máximo infinitas vezes.

Agora, que já deciframos uma parte da regex, falta a outra parte: (\,\d{2})?
Essa parte define os centavos logo, algo assim será aceito: ,00.

\, -> Caracter vírgula (,) com barra de escape para assumir a representação de vírgula.
\d{2} -> Ver explicação acima.
(....) -> Ver explicação acima.
? -> Representa que algo será repetido 0 ou 1 vez.

Agora que já esmiuçamos toda a regex, já entendemos como ela funciona e como ela aceita os valores descritos acima. É só pegar e usar.

Sugestões ? Críticas ? Elogios ? Deixe aí embaixo nos comentários ou, na página do facebook.

Página do facebook: https://www.facebook.com/precisoestudarsempre/

7 comentários:

David disse...

como ficaria essa regex implementada em um método variável.replace() em javaScript?

aditya55 disse...

https://www.welookups.com/sql/sql_dates.html

Preciso estudar sempre disse...

Respondendo ao David...

var someString = 'R$2,00';
var newString = someString.replace(/^R\$(\d{1,3}(\.\d{3})*|\d+)(\,\d{2})?$/, 'string you want to replace');
console.log(newString);

Anônimo disse...

Para não existirem 0 à esquerda nesse RegEx você pode fazer dessa forma:

^R\$([1-9]\d{0,2}((\.\d{3})*|\d*))(\,\d{2})?$

Anônimo disse...

(Mesmo anônimo de cima)

E se você quiser abranger mais moedas (ignorando o padrão de escrita monetário deles e apenas adicionando o símbolo da moeda) você pode fazer essa forma:

^(R\$|\$|€)([1-9]\d{0,2}((\.\d{3})*|\d*))(\,\d{2})?$

Simples, não?

Anônimo disse...

DENTRO DO INPUT TEXT AO DIGITAR FORMATE EM MOEDA REAL COMO FAZER? ME AJUDEM POR FAVO...

oninput="this.value = this.value.replace();"

Preciso estudar sempre disse...

Se você quer que no momento em que o usuário estiver digitando a regex ser aplicada use os eventos onkeypress, onkeyup ou onkeydown. Também é possível usar outros eventos como onblur ou onload. Independentemente do evento construa uma função JavaScripts e ponha a chamada a função no evento do elemento html.

Exemplo:
function coin_mask(value){
....
}

input type="text" onkeypress="coin_mask(this.value)"