繁体   English   中英

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

[英]How can I parse a string with a comma thousand separator to a number?

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

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

是的,删除逗号:

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

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

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

Intl<\/code>对象可能是解决此问题的好方法,但不知何故,他们设法仅使用Intl.NumberFormat.format()<\/code> API 交付规范,而没有parse<\/code>对应项:(

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

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

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

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

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

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

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

令人费解的是,它们包含一个toLocaleString<\/strong>但没有一个parse<\/strong>方法。 IE6+ 至少支持不带参数的toLocaleString<\/strong> 。

对于i18n<\/strong>解决方案,我想出了这个:

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

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

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

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

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

或者试试这个更短的方法:

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]

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

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

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

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

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

var number = '3,456,789.12';
number.split(',').join('');
/* number now equips 3456789.12 */
parseFloat(number);
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,56<\/code>和1,234.56<\/code> ,甚至出现1.234.56<\/code>和1,234,56<\/code>等错误

/**
 * @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);
}
Number("2,299.00".split(',').join(''));   // 2299

如果您想要一个 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, ""));

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

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

基于这里许多伟大的架构师,我对其进行了一些简化。

我更喜欢使用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}`); });

用空字符串替换逗号:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM