JavaScript 是否考虑本地小数分隔符?

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

我有一个网页,以用户的本地化格式显示小数,如下所示:

  • 英语:
    7.75
  • 荷兰语:
    7,75

如果我在我的机器上用 JavaScript 将两个数字变量加在一起(其中数字取自上述格式的字符串),我会得到以下结果:

  • 英语:
    7.75 + 7.75 = 15.5
  • 荷兰语:
    7,75 + 7,75 = 0

如果我要在荷兰用户的计算机上运行此代码,我是否应该期望英语格式的加法返回

0
,而荷兰语格式的加法返回
15,5

简而言之:JavaScript 计算是否在字符串到数字的转换中使用本地小数分隔符?

javascript localization
8个回答
24
投票

这是一个区域设置感知数字解析器的示例:

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

它使用传递的区域设置(如果区域设置参数未定义,则使用浏览器的当前区域设置)来替换千位和小数分隔符。

具有德语区域设置

var n = parseLocaleNumber('1.000.045,22');

n
将等于
1000045.22

更新:

  • 通过使用正则表达式类
    \p{Number}
    删除数字来解决 Pointy 的评论。这样它也适用于非阿拉伯数字。
  • 解决了 Orion Adrian 的评论,以支持数字以每四位数字分隔的语言。
  • 添加了 locale 参数来指定不同的语言环境进行解析。

12
投票

不,在 javascript 中分隔符始终是点 (.)

Number
。因此
7,75
的计算结果为
75
,因为
,
调用从左到右的计算(在控制台中尝试:
x=1,x+=1,alert(x)
,或更确切地说
var x=(7,75); alert(x);
)。如果您想转换荷兰语(嗯,不仅仅是荷兰语,比如说大陆欧洲)格式的值,它应该是
String
。您可以编写
String
原型的扩展,例如:

String.prototype.toFloat = function(){
      return parseFloat(this.replace(/,(\d+)$/,'.$1'));
};
//usage
'7,75'.toFloat()+'7,75'.toFloat(); //=> 15.5

注意,如果浏览器支持就可以使用

Number.toLocaleString

console.log((3.32).toLocaleString("nl-NL"));
console.log((3.32).toLocaleString("en-UK"));
.as-console-wrapper { top: 0; max-height: 100% !important; }


5
投票

扩展@naitsirch的解决方案,我们可以使用Intl.NumberFormat.formatToParts()让JS解析组和小数分隔符。

function parseLocaleNumber(stringNumber) {
  let num = 123456.789,
    fmt_local = new Intl.NumberFormat(),
    parts_local = fmt_local.formatToParts(num),
    group = '',
    decimal = '';

  parts_local.forEach(function(i) {
    switch (i.type) {
      case 'group':
        group = i.value;
        break;
      case 'decimal':
        decimal = i.value;
        break;
      default:
        break;
    }
  });

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

//replace this string with a number formatted for your locale
console.log(parseLocaleNumber("987,654,321.01"));
//output for "en" locale: 987654321.01


3
投票

扩展@OXiGEN 的解决方案,我们可以使用 Intl.NumberFormat.formatToParts() 来提取货币符号:)

function parseLocaleNumber(stringNumber, locale, currency_code) {
  let num = 123456.789,
    fmt_local = new Intl.NumberFormat(locale, {
      style: 'currency',
      currency: currency_code
    }),
    parts_local = fmt_local.formatToParts(num),
    group = '',
    decimal = '',
    currency = '';

  // separators
  parts_local.forEach(function(i) {
    //console.log(i.type + ':' + i.value);
    switch (i.type) {
      case 'group':
        group = i.value;
        break;
      case 'decimal':
        decimal = i.value;
        break;
      case 'currency':
        currency = i.value;
        break;
      default:
        break;
    }
  });

  return parseFloat(stringNumber
    .replace(new RegExp('\\' + group, 'g'), '')
    .replace(new RegExp('\\' + decimal), '.')
    .replace(new RegExp('\\' + currency, 'g'), '')
  );
}

//replace inputs with a number formatted for your locale, your locale code, your currency code
console.log(parseLocaleNumber('$987,654,321.01', 'en', 'USD'));
//output for "en" locale and "USD" code: 987654321.01


2
投票

不,逗号(

,
)是一个具有特殊含义的运算符,就像点(
.
)一样。否则事情就这么简单:

var array1 = [1,2];
var array2 = [1.2];

在不同的语言环境下会崩溃。我所知道的所有主流语言都严格分开对待

.
,
,无论语言环境如何。


1
投票

不,小数点分隔符在 JavaScript 中根本没有本地化,并且 parseFloat() 解析数字的格式与您需要在 JavaScript 源代码中使用的格式相同:“.”作为小数点分隔符,无组(千位)分隔符,“E”或“e”作为“十次方”符号,Ascii 连字符“-”作为减号。

要以本地化格式读取或写入数字,您需要其他东西。我会推荐 Globalize.js 库,除非您可以将自己限制在小数点分隔符和有限数量的语言的单一问题上 - 在这种情况下,仅进行映射“.”的字符串操作可能会更简单。输出时改为“,”,输入时反之亦然。


0
投票

考虑到符号,这在所有情况下都有效:

parseLocaleNumber: function ( stringNumber ) 
{
    let thousandSeparator = (11111).toLocaleString().replace(/1/g, '');
    let decimalSeparator = (1.1).toLocaleString().replace(/1/g, '');
    let symbol = (0).toLocaleString()
        .replace(/0/g, '')
        .replace(new RegExp('\\' + decimalSeparator), '.')
        .trim();

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

突出显示 2 个细节:

  1. 使用 11111 而不是 1111,因为默认情况下第一个总是显示千位分隔符。
  2. 数字格式始终使用“.”作为小数点分隔符

0
投票

基于@stollr 的出色回答。进行调整以规范化空白,其中浏览器将

U+202F
(窄无间断空格)识别为千位分隔符,但用户通常会使用常规空格。

 function parseLocaleNumber(stringNumber, locale) {
    var thousandSeparator = Intl.NumberFormat(locale).format(11111).replace(/\p{Number}/gu, '').replace(/\s+/g, " ");
    var decimalSeparator = Intl.NumberFormat(locale).format(1.1).replace(/\p{Number}/gu, '');

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


parseLocaleNumber('1 234,56', 'fr-FR') // returns 1234.56;
© www.soinside.com 2019 - 2024. All rights reserved.