0
I’m making a <input>
with mask, formatting as user type. In this case, it is a CNPJ entry.
A Regex to format the CNPJ would be /(\d{2})\.?(\d{3})\.?(\d{3})\/?(\d{4})-?(\d+)/g
, but so it format only when Regex is completely satisfied (with all number groups having some non-empty value). Run the code below to view this situation.
const input = document.querySelector('#cnpj');
function onTextChanged(e) {
const text = e.target.value;
const pureText = text.replace(/[^0-9]/g, '');
const textMasked = pureText.replace(
/(\d{2})\.?(\d{3})\.?(\d{3})\/?(\d{4})-?(\d+)/g,
'$1.$2.$3/$4-$5'
);
document.querySelector('#cnpj').value = textMasked;
}
input.addEventListener('input', onTextChanged);
// Automatizando a entrada de dados para exemplificação aqui no Snippet
// Código adaptado de https://stackoverflow.com/a/47617675/8839059
const time = 150;
let current = 0;
let cnpjText = '12345678000123'
function writeText() {
const newValue = input.value + cnpjText[current];
const ev = new Event('input');
input.value = newValue;
input.dispatchEvent(ev);
if (current < cnpjText.length - 1) {
current++;
setTimeout(writeText, time);
} else {
}
}
setTimeout(writeText, time);
<input id="cnpj" maxLength="18" />
I can handle this situation by putting some if
's for the "parts" of Regex:
const input = document.querySelector('#cnpj');
function onTextChanged(e) {
const text = e.target.value;
const pureText = text.replace(/[^0-9]/g, '');
let textMasked = '';
if (pureText.length <= 2) {
textMasked = pureText.replace(
/(\d{2})/g,
'$1'
);
} else if (pureText.length <= 5) {
textMasked = pureText.replace(
/(\d{2})\.?(\d+)/g,
'$1.$2'
);
} else if (pureText.length <= 8) {
textMasked = pureText.replace(
/(\d{2})\.?(\d{3})\.?(\d+)/g,
'$1.$2.$3'
);
} else if (pureText.length <= 12) {
textMasked = pureText.replace(
/(\d{2})\.?(\d{3})\.?(\d{3})\/?(\d+)/g,
'$1.$2.$3/$4'
);
} else {
textMasked = pureText.replace(
/(\d{2})\.?(\d{3})\.?(\d{3})\/?(\d{4})-?(\d+)/g,
'$1.$2.$3/$4-$5'
);
}
document.querySelector('#cnpj').value = textMasked;
}
input.addEventListener('input', onTextChanged);
// Automatizando a entrada de dados para exemplificação aqui no Snippet
// Código adaptado de https://stackoverflow.com/a/47617675/8839059
const time = 150;
let current = 0;
let cnpjText = '12345678000123'
function writeText() {
const newValue = input.value + cnpjText[current];
const ev = new Event('input');
input.value = newValue;
input.dispatchEvent(ev);
if (current < cnpjText.length - 1) {
current++;
setTimeout(writeText, time);
} else {
}
}
setTimeout(writeText, time);
<input id="cnpj" maxLength="18" />
What I’d like to know is how to do something more generic to not need so many if
's.
Great answer. In fact there was "garbage" in Regex because I was trying many different things and ended up going unnoticed. In fact, I was looking around in that reply of Soen who talked about partial matching, was wanting to "generalize" to create a component that would accept any type of mask, but I realized that it would not be worth the benefit cost indeed, would be Regex very complex and maybe slow to perform (I did not analyze the performance)
– Rafael Tavares
@Rafaeltavares In general regex is slower, since the expression needs to be compiled (that’s right, compiled!), an internal structure is generated that the engine will use to execute, the Matches and capture groups have to be generated, what consumes memory, etc. Of course for few small strings, the difference will be inconspicuous, but how to test for your use cases and see if it gets to be a performance problem (and it is worth assessing the cost of maintenance, since the regex of the answer is not so easy to understand and maintain, in my opinion)
– hkotsubo