簡體   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