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

IT技术 javascript localization internationalization
2021-02-16 16:50:51

Intl.NumberFormat(见Mozilla的文档)在Javascript提供了一个很好的方式,以数字格式转换成电流locale`s版本是这样的:

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

但我找不到反转这种格式的方法。有没有像

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

谢谢你的帮助。

6个回答

我找到了一个解决方法:

/**
 * 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 位数字来支持数字每四位分隔的语言。
它不适用于像$ 2,384.21. 它返回NaN
2021-04-20 16:50:51
您可以+在返回之前添加一个符号来强制转换为数字。当我这样做时,我通常也想转换为数值
2021-04-23 16:50:51
解析“123abc”的值给出结果 123 而不是 NaN。
2021-04-28 16:50:51
喜欢这个功能!但请注意,没有必要使用 RegEx 查找千位和小数分隔符。Intl API还提供了formatToParts()功能,容易地提取分离符号:const thousandSeparator = Intl.NumberFormat(i18n.language).formatToParts(11111)[1].value const decimalSeparator = Intl.NumberFormat(i18n.language).formatToParts(1.1)[1].value
2021-05-11 16:50:51

在这里,我创建了一个函数反转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'));

2021-04-20 16:50:51
@OliverJosephAsh 是的,看对了。请记住,并非所有部分都会一直存在。只有千位数字才有千位分隔符,只有小数才有小数点。
2021-04-25 16:50:51
这是正确的想法,但我们一开始使用其他语言环境和格式规则就遇到了问题。有一个被调用的函数formatToParts,它可以用来代替格式来提取组件。然后,您可以从formatToParts函数的该数组中找到分隔符和小数点的正确值
2021-05-02 16:50:51

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

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>

很好的答案,但它有一个问题。没有小数位的数字转换会产生错误的结果。例如。R$ 2.393将结果0.393
2021-05-05 16:50:51

到目前为止,我所做的是一种多步骤方法,您可以在下面的代码中看到。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);
  }
有一个小问题:你必须更换所有的分隔符,所以你必须使用 let thousandSeparator = new RegExp('\\' + comparer[1], 'g');
2021-05-12 16:50:51

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

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(); ?>,但显然可以使用其他答案中建议的除法技巧。