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


104

我有2,299.00一个字符串,我正在尝试将其解析为一个数字。我尝试使用parseFloat,结果为2。我猜逗号是问题所在,但是我将如何以正确的方式解决此问题?只需删除逗号?

var x = parseFloat("2,299.00")
alert(x);

Answers:


121

是的,删除逗号:

parseFloat(yournumber.replace(/,/g, ''));

7
是的,但是现在小数位丢失了。2300.00例如,结果为2300。
user1540714

@ user1540714那是因为它是浮点数而不是字符串。如果随后需要输出,则需要对其进行格式化以始终显示2个小数点。
乔恩·泰勒

可以避免吗?病态尝试toFixed
user1540714 2012年

38
我可以建议我们改为使用以下命令捕获所有逗号:.replace(/,/g, '') 此正则表达式使用全局g替换全部。
gdibble 2015年

32
我不知道为什么这个答案获得如此多的赞誉,并被选为正确答案,它有两个严重的问题。1.它无法处理带有多个逗号的数字,例如parseFloat("2,000,000.00".replace(',',''))返回值2000; 2。在世界上许多,小数位(例如parseFloat("2.000.000,00".replace(',',''))返回值)的区域中,它会失败-有关在世界各地均可使用的2某些信息,请参见下面的答案。
大卫·梅斯特

113

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

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

Intl对象本可以是解决此问题的一种好方法,但是他们设法以某种方式设法仅使用Intl.NumberFormat.format()API而没有parse对应的方式来交付规格:(

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

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


4
不能相信没有人对此答案表示支持,这是此页面上唯一的实际答案!
evilkos

9
完全同意Intl应该有一个解析对手。似乎很明显,人们将需要此。
carlossless

这是执行此操作的唯一系统方法。一种正则表达式适合所有人的方法无法实现这一目标。逗号和句点在不同的语言中具有不同的含义。
Wildhammer

38

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

function parseNumber(value, locale = navigator.language) {
  const example = Intl.NumberFormat(locale).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 }`);
}

他们显然有一些优化和缓存的空间,但这在所有语言中均可靠地起作用。


为什么没有这么多支持!!!这是国际格式的INPUT最优雅的解决方案!谢谢!!
kpollock

法国货币为231123413,12
stackdave

26

删除所有不是数字,小数点或减号(-)的内容:

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, "");

4
这不适用于负数或科学计数法中的数字。
Aadit M Shah 2012年

1
str = str.replace(/(\d+),(?=\d{3}(\D|$))/g, "$1"); 这是我会用的,但是我在regex上完全没用,这是我在其他一些SO线程上找到的。
乔恩·泰勒

@JonTaylor:这里的目的不是验证数字,只是为了使其有效parseFloat-它将对其进行验证。:-)
TJ人群

据我所知,哪个是我的。我用它来将1,234,567等转换为1234567。正如我所说,尽管我在regex上一无是处,所以我一辈子都不能告诉你它实际上在做什么。
乔恩·泰勒

1
删除“-”减号的好主意-获得完全相同的其他数字,并且如果您解析异构格式,则“ 7.500”!==“ 7,500”
Serge

14

通常,您应该考虑使用不允许将自由文本输入为数值的输入字段。但是在某些情况下,您需要猜测输入格式。例如,德国的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
Goferito先生17年

谢谢Goferito先生-对不起-我已修复此功能。
Gerfried

例如,在法国语言环境中,这看起来也可能会因为非常小的数字“ 0,124”而失败。
Paul Alexander

哇,太好了!这几乎是我一直在寻找的:3,00 €也被替换为3.00。请注意,其3,001格式为3001。为避免这种情况,输入应始终使用十进制符号。例如3,001.00€ 3,001.00正确转换。另外,请更新jsfiddle。0,124仍然转换为124
Arnis Juraga '17

做得很好的伙伴,我认为值得正确答案
Waheed

5

令人困惑的是它们包括一个toLocaleString而不是一个parse方法。IE6 + 至少支持不带参数的toLocaleString

对于i18n解决方案,我提出了以下建议:

首先检测用户的语言环境小数点分隔符:

var decimalSeparator = 1.1;
decimalSeparator = decimalSeparator.toLocaleString().substring(1, 2);

如果字符串中有多个小数点分隔符,则对数字进行归一化:

var pattern = "([" + decimalSeparator + "])(?=.*\\1)";separator
var formatted = valor.replace(new RegExp(pattern, "g"), "");

最后,删除所有非数字或小数点分隔符的内容:

formatted = formatted.replace(new RegExp("[^0-9" + decimalSeparator + "]", "g"), '');
return Number(formatted.replace(decimalSeparator, "."));

5

这是该parseFloat函数的一个简单的,不打扰的包装器。

function parseLocaleNumber(str) {
  // Detect the user's locale decimal separator:
  var decimalSeparator = (1.1).toLocaleString().substring(1, 2);
  // Detect the user's locale thousand separator:
  var thousandSeparator = (1000).toLocaleString().substring(1, 2);
  // In case there are locales that don't use a thousand separator
  if (thousandSeparator.match(/\d/))
    thousandSeparator = '';

  str = str
    .replace(new RegExp(thousandSeparator, 'g'), '')
    .replace(new RegExp(decimalSeparator), '.')

  return parseFloat(str);
}

2

如果要避免David Meister发布的问题并且确定小数位数,可以替换所有点和逗号并除以100,例如:

var value = "2,299.00";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/100;

或如果您有3位小数

var value = "2,299.001";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/1000;

是否要使用parseInt,parseFloat或Number取决于您。另外,如果要保留小数位数,可以使用函数.toFixed(...)。


1

如果您有数百万个数字,则所有这些答案都将失败。

3,456,789将使用replace方法简单地返回3456。

简单删除逗号的最正确答案必须是。

var number = '3,456,789.12';
number.split(',').join('');
/* number now equips 3456789.12 */
parseFloat(number);

或简单地写。

number = parseFloat(number.split(',').join(''));

当然,美国人使用逗号而不是点。试图制造一个怪兽来尝试同时处理这两者是愚蠢的。
案例

2
但是这种“怪异”已经作为Unicode提供的一部分存在(请参阅我的回答)。我敢肯定,如果您与国际客户一起经营一家公司,您会对此感到不那么愚蠢。
大卫·迈斯特

1

这会将任何语言环境中的数字转换为普通数字。也适用于小数点:

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

1

使用此功能,您将能够以1.234,56和的多种格式设置值的格式1,234.56,甚至会出现诸如1.234.56和的错误。1,234,56

/**
 * @param {string} value: value to convert
 * @param {bool} coerce: force float return or NaN
 */
function parseFloatFromString(value, coerce) {
    value = String(value).trim();

    if ('' === value) {
        return value;
    }

    // check if the string can be converted to float as-is
    var parsed = parseFloat(value);
    if (String(parsed) === value) {
        return fixDecimals(parsed, 2);
    }

    // replace arabic numbers by latin
    value = value
    // arabic
    .replace(/[\u0660-\u0669]/g, function(d) {
        return d.charCodeAt(0) - 1632;
    })

    // persian
    .replace(/[\u06F0-\u06F9]/g, function(d) {
        return d.charCodeAt(0) - 1776;
    });

    // remove all non-digit characters
    var split = value.split(/[^\dE-]+/);

    if (1 === split.length) {
        // there's no decimal part
        return fixDecimals(parseFloat(value), 2);
    }

    for (var i = 0; i < split.length; i++) {
        if ('' === split[i]) {
            return coerce ? fixDecimals(parseFloat(0), 2) : NaN;
        }
    }

    // use the last part as decimal
    var decimal = split.pop();

    // reconstruct the number using dot as decimal separator
    return fixDecimals(parseFloat(split.join('') +  '.' + decimal), 2);
}

function fixDecimals(num, precision) {
    return (Math.floor(num * 100) / 100).toFixed(precision);
}
parseFloatFromString('1.234,56')
"1234.56"
parseFloatFromString('1,234.56')
"1234.56"
parseFloatFromString('1.234.56')
"1234.56"
parseFloatFromString('1,234,56')
"1234.56"

0

如果您想要一个10n的答案,请按照这种方式进行。示例使用货币,但是您不需要。如果必须支持较旧的浏览器,则需要对Intl库进行填充。

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, ""));

9
这并不是真正的答案,因为对于某些语言环境(例如DE),逗号是小数点。
Andreas

并且replace()仅在不RegExp'g'标志一起使用时才替换第一个匹配项。
Binki'1

@binki谢谢。固定。
Tony Topper

@Andreas这是l10n的答案。如果您想要其他货币,则只需将currencyId的值更改为该国家的currencyId。
Tony Topper

1
@TonyTopper,这不会改变以下事实:,在某些区域设置中,用逗号分隔符将千位分隔符的替换硬编码到其中
Andreas

0

用空字符串替换逗号:

var x = parseFloat("2,299.00".replace(",",""))
alert(x);


这不安全。如其他答案所述,在世界许多地方,逗号代表小数点。
大卫·迈斯特

1
同样,此方法在2,299,000.00上不起作用,因为它将仅替换第一个逗号
wizulus,

0

如果您要支持的语言环境很少,那么只需对一些简单规则进行硬编码可能会更好:

function parseNumber(str, locale) {
  let radix = ',';
  if (locale.match(/(en|th)([-_].+)?/)) {
    radix = '.';
  }
  return Number(str
    .replace(new RegExp('[^\\d\\' + radix + ']', 'g'), '')
    .replace(radix, '.'));
}

0
const parseLocaleNumber = strNum => {
    const decSep = (1.1).toLocaleString().substring(1, 2);
    const formatted = strNum
        .replace(new RegExp(`([${decSep}])(?=.*\\1)`, 'g'), '')
        .replace(new RegExp(`[^0-9${decSep}]`, 'g'), '');
    return Number(formatted.replace(decSep, '.'));
};

0
Number("2,299.00".split(',').join(''));   // 2299

split函数使用“,”作为分隔符将字符串拆分为一个数组,并返回一个数组。
join函数连接从split函数返回的数组元素。
Number()函数将连接的字符串转换为数字。


请详细说明什么是解决方案以及如何解决该问题。
塔里克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.