我如何解析一个字符串与逗号千分隔符为一个数字?

我将 2,299.00作为一个字符串,并尝试将其解析为一个数字。我尝试使用 parseFloat,结果是2。我想逗号是问题所在,但我怎样才能正确地解决这个问题呢?去掉逗号?

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

183964 次浏览

删除任何非数字、小数点或负号(-)的内容:

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

是的,删除逗号:

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

如果你想知道答案,这样做。示例使用货币,但是您不需要它。如果您必须支持较老的浏览器,则需要填充 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, ""));

如果你有一个数以百万计的数字,所有这些答案都会失败。

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(''));

删除逗号有潜在的危险,因为正如其他人在注释中提到的,许多地区使用逗号来表示不同的意思(比如小数位)。

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

Intl对象可能是解决这个问题的一个很好的方法,但是不知怎么的,他们设法只提供了一个 Intl.NumberFormat.format() API 而没有 parse对应的规范: (

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

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

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

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

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

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

如果您需要支持一小组地区,那么最好是硬编码一些简单的规则:

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

令人困惑的是,他们包括一个 ToLocaleString而不是一个 解析方法。至少在 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, "."));

如果你想避免 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,这取决于您。另外,如果你想保留小数位数,你可以使用这个函数。固定(...)。

这会将任意区域的数字转换为正常数字。 对小数点也有效:

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

使用这个函数,您将能够格式化多种格式的值,如 1.234,561,234.56,甚至使用像 1.234.561,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"
Number("2,299.00".split(',').join(''));   // 2299


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

或者尝试这种 更短方法:

const myNum =  +('2,299.00'.replace(",",""));

如果有几个逗号,使用正则表达式:

const myNum =  +('2,022,233,988.55'.replace(/,/g,""));
// -> myNum = 2022233988.55

下面是 我的情况在一个数组中(用于类似的用例) :

要得到这个数组的和:

const numbers = ["11", "7", "15/25", "18/5", "12", "16/25"]

通过使用 parseFloat,我将丢失小数,因此为了得到 具体数目,我必须首先用点替换斜杠,然后将字符串转换为实际的数字。

所以:

const currectNumbers = numbers.map(num => +(num.replace("/",".")))


// or the longer approach:
const currectNumbers = numbers
.map(num => num.replace("/","."))
.map(num => parseFloat(num));

这将为我提供在 reduce 方法中使用的所需数组:

currectNumbers = [ 11, 7, 15.25, 18.5, 12, 16.25]

基于这里许多伟大的建筑师,我已经简化了一点。

我更喜欢使用 Intl.NumberFormat(undefined)来使它使用 best fit机制。

如果用户像我一样,有一个丹麦式的键盘,但是更喜欢 Mac 是英文的,这会有所帮助: if (Number.isNaN(normalized)) return Number(value.replace(',', '.'));

如果这在表单中使用,我发现应该使用 inputMode="numeric"而不是 type="number"

function parseNumber(value, locales = undefined) {
if (typeof value !== 'string') return value;
const example = Intl.NumberFormat(locales).format('1.1');
const normalized = Number(value.replace(example.charAt(1), '.'));
if (Number.isNaN(normalized)) return Number(value.replace(',', '.'));
return normalized;
}


/* test */


const tests = [
{
locale: 'en-US',
candidate: 1.123,
expected: 1.123,
},
{
locale: 'en-US',
candidate: '1.123',
expected: 1.123,
},
{
locale: 'fr-FR',
candidate: '33.123',
expected: 33.123,
},
{
locale: 'fr-FR',
candidate: '33,123',
expected: 33.123,
},
{
locale: 'da-DK',
candidate: '45.123',
expected: 45.123,
},
{
locale: 'da-DK',
candidate: '45,123',
expected: 45.123,
},
{
locale: 'en-US',
candidate: '0.123',
expected: 0.123,
},
{
locale: undefined,
candidate: '0,123',
expected: 0.123,
},
];


tests.forEach(({ locale, candidate, expected }) => {
const parsed = parseNumber(candidate, locale);
console.log(`${candidate} as ${typeof candidate} in ${locale}: ${parsed} === ${expected}? ${parsed === expected}`);
});