A Simple Solution for Parsing Localized Numbers in JavaScript
I recently published a simple tool for calculating how adding water to a glass of whisky changes the alcohol strength.
Because the user should be able to enter numbers with a precision of 0.1 or even 0.01, I was faced with a classic localization problem: numbers are formatted differently in different cultures.
US-based users write 1,234.5
. In Germany or France, the same number could be written 1.234,5
. Actually, my guess is that most people would even omit the thousand separator altogether and write either 1234.5
or 1234,5
.
Now, formatting a number in the user’s locale is easy. With:
num.toLocaleString(undefined, { maximumFractionDigits: 2})
I can output the number with 2 fraction digits precision, just the way the user would expect to see them based on their browser’s language settings.
But there isn’t an out-of-the-box way of parsing such numbers. Doing so with perfect accuracy is probably very hard and would require importing a comprehensive set of culture-specific rules, and also knowing which one to apply. I just needed a simple solution that would work in 99,9% of cases, though. (Or 99.9%, as my spellchecker points out…)
I went with a simple solution:
function parseUserNumber(s) {
const c = s.indexOf(',');
const p = s.indexOf('.');
if (c == -1) {
// No comma at all, life is good.
return parseFloat(s);
}
else if (p == -1) {
// No period at all. Assume comma used as decimal sign, replace with period.
return parseFloat(s.replace(',', '.'));
}
else if (c < p) {
// Something resembling 1,234.5: Assume comma is thousands separator, just remove.
return parseFloat(s.replaceAll(',', ''));
}
else {
// Something resembling 1.234,5: Remove period, then replace comma with period.
return parseFloat(s.replaceAll('.', '').replace(',', '.'));
}
}
In the function above, s is assumed to be a string. Add your own solution to handle other types as needed.
You can try it out here:
There’s probably more accurate ways of doing it, and, acknowledging this is a very western-centric solution, there are possibly locales in which this doesn’t quite work. You probably don’t want to use this for a financial application (you don’t want to use JavaScript Numbers for this in any case). But this solution is simple, works in all cases I could think of, and is good enough in a context where performance when converting user input is not a concern.
Found a bug? Report an issue on GitHub. Thanks!