How can I parse a string with a comma thousand separator to a number?

后端 未结 16 2587
被撕碎了的回忆
被撕碎了的回忆 2020-11-22 10:18

I have 2,299.00 as a string and I am trying to parse it to a number. I tried using parseFloat, which results in 2. I guess the comma is the problem

相关标签:
16条回答
  • 2020-11-22 10:46

    Usually you should consider to use input fields which don't allow free text input for numeric values. But there might be cases, when you need to guess the input format. For example 1.234,56 in Germany means 1,234.56 in US. See https://salesforce.stackexchange.com/a/21404 for a list of countries which use comma as decimal.

    I use the following function to do a best guess and strip off all non-numeric characters:

    function parseNumber(strg) {
        var strg = strg || "";
        var decimal = '.';
        strg = strg.replace(/[^0-9$.,]/g, '');
        if(strg.indexOf(',') > strg.indexOf('.')) decimal = ',';
        if((strg.match(new RegExp("\\" + decimal,"g")) || []).length > 1) decimal="";
        if (decimal != "" && (strg.length - strg.indexOf(decimal) - 1 == 3) && strg.indexOf("0" + decimal)!==0) decimal = "";
        strg = strg.replace(new RegExp("[^0-9$" + decimal + "]","g"), "");
        strg = strg.replace(',', '.');
        return parseFloat(strg);
    }   
    

    Try it here: https://plnkr.co/edit/9p5Y6H?p=preview

    Examples:

    1.234,56 € => 1234.56
    1,234.56USD => 1234.56
    1,234,567€ => 1234567
    1.234.567 => 1234567
    1,234.567 => 1234.567
    1.234 => 1234 // might be wrong - best guess
    1,234 => 1234 // might be wrong - best guess
    1.2345 => 1.2345
    0,123 => 0.123
    

    The function has one weak point: It is not possible to guess the format if you have 1,123 or 1.123 - because depending on the locale format both might be a comma or a thousands-separator. In this special case the function will treat separator as a thousands-separator and return 1123.

    0 讨论(0)
  • 2020-11-22 10:47

    On modern browsers you can use the built in Intl.NumberFormat to detect the browser's number formatting and normalize the input to match.

    function parseNumber(value, locales = navigator.languages) {
      const example = Intl.NumberFormat(locales).format('1.1');
      const cleanPattern = new RegExp(`[^-+0-9${ example.charAt( 1 ) }]`, 'g');
      const cleaned = value.replace(cleanPattern, '');
      const normalized = cleaned.replace(example.charAt(1), '.');
    
      return parseFloat(normalized);
    }
    
    const corpus = {
      '1.123': {
        expected: 1.123,
        locale: 'en-US'
      },
      '1,123': {
        expected: 1123,
        locale: 'en-US'
      },
      '2.123': {
        expected: 2123,
        locale: 'fr-FR'
      },
      '2,123': {
        expected: 2.123,
        locale: 'fr-FR'
      },
    }
    
    
    for (const candidate in corpus) {
      const {
        locale,
        expected
      } = corpus[candidate];
      const parsed = parseNumber(candidate, locale);
    
      console.log(`${ candidate } in ${ corpus[ candidate ].locale } == ${ expected }? ${ parsed === expected }`);
    }

    Their's obviously room for some optimization and caching but this works reliably in all languages.

    0 讨论(0)
  • 2020-11-22 10:47

    If you want a l10n answer do it this way. Example uses currency, but you don't need that. Intl library will need to be polyfilled if you have to support older browsers.

    var value = "2,299.00";
    var currencyId = "USD";
    var nf = new Intl.NumberFormat(undefined, {style:'currency', currency: currencyId, minimumFractionDigits: 2});
    
    value = nf.format(value.replace(/,/g, ""));
    
    0 讨论(0)
  • 2020-11-22 10:48

    This converts a number in whatever locale to normal number. Works for decimals points too:

    function numberFromLocaleString(stringValue, locale){
        var parts = Number(1111.11).toLocaleString(locale).replace(/\d+/g,'').split('');
        if (stringValue === null)
            return null;
        if (parts.length==1) {
            parts.unshift('');
        }   
        return Number(String(stringValue).replace(new RegExp(parts[0].replace(/\s/g,' '),'g'), '').replace(parts[1],"."));
    }
    
    //Use default browser locale
    numberFromLocaleString("1,223,333.567") //1223333.567
    
    //Use specific locale
    numberFromLocaleString("1 223 333,567", "ru") //1223333.567
    
    0 讨论(0)
提交回复
热议问题