有没有办法通过JavaScript中的Intl.NumberFormat反转格式

问题描述 投票:0回答:11

Intl.NumberFormat
(请参阅Mozilla 的文档)在 Javascript 中提供了一种将数字格式化为当前语言环境版本的好方法,如下所示:

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

但我找不到扭转这种格式的方法。 有没有类似的东西

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

感谢您的帮助。

javascript localization internationalization
11个回答
52
投票

我找到了解决方法:

/**
 * 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), '.')
    );
}

像这样使用它:

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

不是最好的解决方案,但它有效:-)

如果有人知道实现此目标的更好方法,请随时发布您的答案。

更新

  • 封装在一个完整的可重用功能中
  • 使用正则表达式类
    \p{Number}
    提取分隔符。这样它也适用于非阿拉伯数字。
  • 使用 5 位数字来支持数字每四位分隔一次的语言。

18
投票

在这里,我创建了一个用于反转

format()
函数的函数。 此功能将支持所有语言环境中的反向格式。

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'));


4
投票

我刚刚使用组替换器解决了它

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>


4
投票

您可以使用实例上可用的 formatToParts 方法,这通常更好,因为您可以通过这种方式忽略货币和组分隔符

  function convertToFloat(number, locale = 'en', currency = 'AUD') {
  const instance = new Intl.NumberFormat(locale, {
    style: 'currency',
    currency,
  });
  const roundedValue = instance.formatToParts(number)
    .filter(part => !['currency', 'group'].includes(part.type))
    .reduce((acc, part) => `${acc}${part.value}`, '').replace(/,/g, '.');
  // then just parse it as a float
  return [instance.format(number), '->', parseFloat(roundedValue)];
}
console.log(convertToFloat(1234.56)); // -> 1234.56
console.log(convertToFloat(1234.56, 'de-DE', 'EUR')); // -> 1234.56


2
投票

到目前为止我所做的是一种多步骤方法,您可以在下面的代码中看到。 nf 是 NumberFormat 服务。此函数采用格式化的数字以及使用的区域设置。现在我们通过将 10k 除以 3 创建一个比较器,从而保证小数和千位分隔符位于固定位置。然后删除千位分隔符和所有其他非数字符号,例如货币符号。之后我们将小数点分隔符替换为英文分隔符,最后返回一个转换后的数字。

  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);
  }

0
投票

这是我的看法,使用

formatToParts

它将处理字符串前缀或后缀的任何额外内容。当您使用 AntD 的

NumberInput
组件和自定义
formatter
时,这一点通常很重要,例如渲染
%
,或使用
Intl.NumberFormat
渲染货币符号。

const parseLocaleNumber = (locale, str, opts) => {
  const sampleValueParts = Intl.NumberFormat(locale, {
    ...opts,
    minimumIntegerDigits: 4,  // make sure the thousand separator is included
    minimumFractionDigits: 2, // make sure the decimal separator is included
  }).formatToParts(0);

  const usefulParts = ['integer', 'fraction', 'decimal'];
  const unusefulParts = sampleValueParts.filter(({ type }) => !usefulParts.includes(type));

  // remove unuseful parts from the string
  // (mainly the thousand separator)
  let cleanedStr = unusefulParts.reduce(
    (updatedStr, part) => updatedStr.replace(part.value, ''),
    str
  );

  // replace the decimal separator with the standard decimal separator
  const decimalCh = sampleValueParts.find(({ type }) => type === 'decimal')?.value;
  if (decimalCh) {
    cleanedStr = cleanedStr.split(decimalCh).join('.');
  }

  // remove everything except digits and decimal point
  return parseFloat(cleanedStr.match(/[\d.]+/)?.[0] ?? 'NaN');
};

用途:

parseLocaleNumber('en', '1,234.56'); // 1234.56
parseLocaleNumber('de', '1.234,56'); // 1234.56

parseLocaleNumber('en', 'CAD 1,234.56'); // 1234.56
parseLocaleNumber('en', '1,234.56 CAD'); // 1234.56

parseLocaleNumber('en', 'whatever'); // NaN

-1
投票

不确定这种方法在性能方面的相关性,但有多种选择总是好的,所以这里是另一种:

function getNumPrice(price, decimalpoint) {
    var p = price.split(decimalpoint);
    for (var i=0;i<p.length;i++) p[i] = p[i].replace(/\D/g,'');
    return p.join('.');
}

在我的例子中,语言环境是从 PHP 设置的,所以我用

<?php echo cms_function_to_get_decimal_point(); ?>
来获取它,但显然可以使用其他答案中建议的除法技巧。


-1
投票

我已经尝试过接受的答案并同意这一点。所以我也投了赞成票。我可能有另一种解决方法,无需指定任何本地内容,而是手动查找分隔符。

P.s.数字参数用于指定小数位数。

parseLocaleNumber(stringnum: string, digit: number): number {
    let retValue: number = parseFloat(stringnum);
    var arr: string[] = stringnum.split('');
    arr.slice().reverse().forEach((x, i, arr) => {
        if (i === digit) {
            if (x === '.') {
                retValue = parseFloat(stringnum.split(',').join(''));
                arr.length = i + 1;
            } else if (x === ',') {
                retValue = parseFloat(stringnum.split('.').join(''));
                arr.length = i + 1;
            }
        }
    });
    return retValue;
}

使用此方法的示例:

console.log(parseLocaleNumber('123,456,789.12'));
// 123456789.12

代码是使用 TypeScript 编写的。


-3
投票

您应该能够使用:

value.replace(/\D/g, '');

因为任何添加的格式都将是非数字


-3
投票

不是很干净,但对我有用:

//value is "in-En" format --> $1,200.51
function unformatter(value){
    value = value.replace("$","");
    value = value.replace(",","");
    value = parseFloat(value);
    return(value); //returns --> 1200.51
};

-3
投票

也许是一个虚拟解决方案

const getInformattedMoney = (formattedValue) => Number(formmattedValue.replaceAll('.','').replaceAll(',','.').replace(`${currencySymbol}`,''))

对我来说,

.
(点)是千位分隔符,
,
(逗号)是双分隔符

© www.soinside.com 2019 - 2024. All rights reserved.