Is there a way to reverse the formatting by Intl.NumberFormat in JavaScript

The Intl.NumberFormat (see Mozilla's doc) provides a nice way in Javascript to format numbers into a current locale`s version like this:

new Intl.NumberFormat().format(3400); // returns "3.400" for German locale

But I couldn't find a way to reverse this formatting. Is there something like

new Intl.NumberFormat().unformat("3.400"); // returns 3400 for German locale

Thanks for any help.


I have found a workaround:

/**
 * Parse a localized number to a float.
 * @param {string} stringNumber - the localized number
 * @param {string} locale - [optional] the locale that the number is represented in. Omit this parameter to use the current locale.
 */
function parseLocaleNumber(stringNumber, locale) {
    var thousandSeparator = Intl.NumberFormat(locale).format(11111).replace(/\p{Number}/gu, '');
    var decimalSeparator = Intl.NumberFormat(locale).format(1.1).replace(/\p{Number}/gu, '');

    return parseFloat(stringNumber
        .replace(new RegExp('\\' + thousandSeparator, 'g'), '')
        .replace(new RegExp('\\' + decimalSeparator), '.')
    );
}

Using it like this:

parseLocaleNumber('3.400,5', 'de');
parseLocaleNumber('3.400,5'); // or if you have German locale settings
// results in: 3400.5

Not the nicest solution but it works :-)

If anyone knows a better way of achieving this, feel free to post your answer.

Update

  • Wrapped in a complete reusable function
  • Using the regex class \p{Number} to extract the separator. So that it also works with non-arabic digits.
  • Using number with 5 places to support languages where numbers are separated at every fourth digit.

Here I have created a function for Reverse of format() function. This function will support reverse formatting in all locales.

function reverseFormatNumber(val,locale){
        var group = new Intl.NumberFormat(locale).format(1111).replace(/1/g, '');
        var decimal = new Intl.NumberFormat(locale).format(1.1).replace(/1/g, '');
        var reversedVal = val.replace(new RegExp('\\' + group, 'g'), '');
        reversedVal = reversedVal.replace(new RegExp('\\' + decimal, 'g'), '.');
        return Number.isNaN(reversedVal)?0:reversedVal;
    }

console.log(reverseFormatNumber('1,234.56','en'));
console.log(reverseFormatNumber('1.234,56','de'));

I just solved it using group replacers

const exp = /^\w{0,3}\W?\s?(\d+)[.,](\d+)?,?(\d+)?$/g
const replacer = (f, group1, group2, group3) => {
return group3 ? 
            `${group1}${group2}.${group3}` : 
            `${group1}.${group2}`
}


const usd = '$10.15'.replace(exp, replacer)
// 10.15

const eu = '€01.25'.replace(exp, replacer)
// 1.25

const brl = 'R$ 14.000,32'.replace(exp, replacer)
// 14000.32

const tai = 'TAI 50.230,32'.replace(exp, replacer)
// 50230.32


// just to test!
const el = document.getElementById('output')

const reverseUSD = new Intl.NumberFormat('en-us', { style: 'currency', currency: 'USD' }).format(usd)

el.innerHTML += `<br> from: ${reverseUSD} to ${parseFloat(usd)}`

const reverseBRL = new Intl.NumberFormat('pt-br', { style: 'currency', currency: 'BRL' }).format(brl)

el.innerHTML += `<br> from: ${reverseBRL} to ${parseFloat(brl)}`

const reverseTAI = new Intl.NumberFormat('en-us', { style: 'currency', currency: 'TAI' }).format(tai)

el.innerHTML += `<br> from: ${reverseTAI} to ${parseFloat(tai)}`

const reverseEU = new Intl.NumberFormat('eur', { style: 'currency', currency: 'EUR' }).format(eu)

el.innerHTML += `<br> from: ${reverseEU} to ${parseFloat(eu)}`
<output id=output></output>

what I've done so far is a multi step approach which you can see in the below code. nf is the NumberFormat service. This function takes the formatted number as well as the used locale. Now we create a comparator by dividing 10k by 3 thus guaranteeing a decimal and thousandSeparator at a fixed position. Then remove the thousand separator and all other non-numeric signs, like currency symbols. after that we replace the decimal separator with the english one and finally return a casted number.

  uf(number, locale) {
    let nf = this.nf({}, locale);
    let comparer = nf.format(10000 / 3);

    let thousandSeparator = comparer[1];
    let decimalSeparator = comparer[5];

    // remove thousand seperator
    let result = number.replace(thousandSeparator, '')
    // remove non-numeric signs except -> , .
      .replace(/[^\d.,-]/g, '')
    // replace original decimalSeparator with english one
      .replace(decimalSeparator, '.');

    // return real number
    return Number(result);
  }