如何将带有逗号千位分隔符的字符串解析为数字?

IT技术 javascript number-formatting
2021-01-12 01:08:54

我有2,299.00一个字符串,我试图将它解析为一个数字。我尝试使用parseFloat,结果为 2。我想逗号是问题所在,但我将如何以正确的方式解决此问题?去掉逗号就可以了?

var x = parseFloat("2,299.00")
console.log(x);

6个回答

是删除逗号:

let output = parseFloat("2,299.00".replace(/,/g, ''));
console.log(output);

是的,但现在小数位丢失了。例如,2300.00 结果为 2300。
2021-03-14 01:08:54
我可以建议我们改为使用以下方法捕获所有逗号:.replace(/,/g, '') 此正则表达式使用全局g替换全部。
2021-03-19 01:08:54
@user1540714 那是因为它是一个浮点数而不是一个字符串。如果您需要输出它,您需要将其格式化为始终显示 2 个小数点。
2021-04-03 01:08:54
我不知道为什么这个答案得到了如此多的赞成并被选为正确的,它有两个严重的问题。1. 它不能处理带有多个逗号的数字,例如parseFloat("2,000,000.00".replace(',',''))返回2000和 2. 它在世界上许多地区都失败了,其中,小数位是小数位,例如parseFloat("2.000.000,00".replace(',',''))返回2- 请参阅下面我的答案,了解在世界任何地方都可以使用的东西。
2021-04-04 01:08:54
在法语语言环境中,逗号是小数点分隔符......因此,对于浏览器设置了法语语言环境的很可能情况,这将失败
2021-04-08 01:08:54

删除逗号有潜在危险,因为正如其他人在评论中提到的那样,许多语言环境使用逗号来表示不同的东西(如小数位)。

我不知道你从哪里得到你的字符串,但在世界上的某些地方"2,299.00"=2.299

Intl对象可能是解决此问题的好方法,但不知何故,他们设法仅使用Intl.NumberFormat.format()API 而没有parse对应物来发布规范:(

以任何 i18n 理智的方式将包含文化数字字符的字符串解析为机器可识别的数字的唯一方法是使用利用 CLDR 数据的库来覆盖格式化数字字符串的所有可能方式http://cldr.unicode。组织/

到目前为止,我遇到的两个最好的 JS 选项:

完全同意 Intl 应该有一个解析对应物。很明显,人们会需要这个。
2021-03-23 01:08:54
这是做到这一点的唯一系统方法。不能用一种正则表达式万能的方法来实现这一点。逗号和句号在不同的语言中具有不同的含义。
2021-03-24 01:08:54
不能相信还没有人赞成这个答案,这是此页面上唯一的实际答案!
2021-03-31 01:08:54

在现代浏览器上,您可以使用内置的Intl.NumberFormat来检测浏览器的数字格式并将输入规范化以匹配。

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

它们显然有一些优化和缓存的空间,但这在所有语言中都可以可靠地工作。

在法国货币是 231 123 413,12
2021-03-20 01:08:54
为什么这没有得到大量的赞成!!!它是国际格式输入的最优雅的解决方案!谢谢!!
2021-03-27 01:08:54
如果您需要支持 IE11,请将第 3 行替换为:const cleanPattern = new RegExp("[^-+0-9" + example.charAt( 1 ) + "]", 'g');- IE 不支持模板字符串“`” - caniuse.com/#search=template%20string
2021-04-02 01:08:54
传递navigator.languages而不是传递navigator.language给构造函数不是更好吗?我想知道因为在“不耐烦的现代 JavaScript”一书中,它建议使用那个。不知道有什么区别
2021-04-07 01:08:54
@KoheiNozaki 我又看了一眼Locale 谈判,看来您正在做某事。如果您将所有这些都传入,浏览器应该协商首选语言环境,这样就不会有什么坏处,并且最好将它们全部传入。
2021-04-07 01:08:54

删除任何不是数字、小数点或减号 ( -) 的内容:

var str = "2,299.00";
str = str.replace(/[^\d\.\-]/g, ""); // You might also include + if you want them to be able to type it
var num = parseFloat(str);

更新的小提琴

请注意,它不适用于科学记数法中的数字。如果你想让它,改变replace行添加eE+到可接受的字符列表:

str = str.replace(/[^\d\.\-eE+]/g, "");
据我所知,我的确实这样做了。我用它来将 1,234,567 等转换为 1234567。正如我所说,虽然我在正则表达式方面完全没用,所以我一生都无法告诉你它实际上做了什么,哈哈。
2021-03-12 01:08:54
删除“-”减号的坏主意 - 完全获得其他数字,并且如果您解析异构格式,“7.500”!==“7,500”
2021-03-13 01:08:54
这不适用于负数或科学记数法中的数字。
2021-03-22 01:08:54
@JonTaylor:这里的目标不是验证数字,只是让它起作用parseFloat——这将验证它。:-)
2021-03-24 01:08:54
str = str.replace(/(\d+),(?=\d{3}(\D|$))/g, "$1"); 这是我会使用的,但我在正则表达式中完全没用,这是我在其他一些 SO 线程上发现的东西。
2021-04-03 01:08:54

通常您应该考虑使用不允许对数值进行自由文本输入的输入字段。但在某些情况下,您可能需要猜测输入格式。例如,德国的 1.234,56 表示美国的 1,234.56。有关使用逗号作为十进制的国家/地区列表,请参阅https://salesforce.stackexchange.com/a/21404

我使用以下函数进行最佳猜测并去除所有非数字字符:

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

在这里试试:https : //plnkr.co/edit/9p5Y6H?p=preview

例子:

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

该函数有一个弱点:如果您有 1,123 或 1.123,则无法猜测格式 - 因为根据区域设置格式,两者都可能是逗号或千位分隔符。在这种特殊情况下,该函数会将分隔符视为千位分隔符并返回 1123。

对于像 1,111.11 这样的数字失败,这显然是英文格式,但返回 111111
2021-03-13 01:08:54
哇,太好了!这几乎正​​是我正在寻找的:3,00 €也被替换为 3.00。只是一个注释,它3,001被格式化为3001. 为避免这种情况,输入应始终使用十进制符号。例如3,001.00€ 3,001.00正确转换。另外,请更新jsfiddle。0,124仍然转换为 124
2021-03-20 01:08:54
干得好,伙计,我认为值得成为正确答案
2021-03-25 01:08:54
谢谢你,Goferito 先生 - 对不起 - 我修复了这个功能。
2021-04-01 01:08:54
例如,看起来这对于法语语言环境中的非常小的数字“0,124”也可能失败。
2021-04-07 01:08:54