138

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

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

4

14 回答 14

164

是的,删除逗号:

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

于 2012-07-26T09:08:50.553 回答
154

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

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

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

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

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

于 2017-02-02T10:45:52.080 回答
53

在现代浏览器上,您可以使用内置的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 }`);
}

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

于 2017-07-25T16:44:56.603 回答
25

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

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行更改为添加e, E, 和+可接受的字符列表:

str = str.replace(/[^\d\.\-eE+]/g, "");
于 2012-07-26T09:06:45.573 回答
17

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

于 2017-04-17T09:37:19.957 回答
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, "."));
于 2018-07-03T14:54:08.967 回答
3

如果您想避免 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(...)。

于 2019-04-04T12:37:15.307 回答
2

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

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
于 2019-10-22T21:39:22.520 回答
1

如果您有数百万的数字,所有这些答案都会失败。

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

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

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

或者简单地写。

number = parseFloat(number.split(',').join(''));
于 2016-07-21T18:36:19.297 回答
1
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, '.'));
};
于 2020-03-19T03:23:43.540 回答
1

使用此功能,您将能够以多种格式格式化值,例如1.234,56and 1,234.56,甚至出现 and 等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"
于 2020-05-06T11:40:58.090 回答
1
Number("2,299.00".split(',').join(''));   // 2299

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

于 2020-06-08T05:14:47.613 回答
0

如果您想要一个 l10n 答案,请这样做。示例使用货币,但您不需要它。如果您必须支持旧版浏览器,则需要对 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, ""));
于 2015-03-13T22:09:11.500 回答
0

如果你有一小部分语言环境来支持你可能会更好地通过硬编码几个简单的规则:

function parseNumber(str, locale) {
  let radix = ',';
  if (locale.match(/(en|th)([-_].+)?/)) {
    radix = '.';
  }
  return Number(str
    .replace(new RegExp('[^\\d\\' + radix + ']', 'g'), '')
    .replace(radix, '.'));
}
于 2018-03-02T12:22:05.547 回答