Як я можу розібрати рядок з роздільником тисячі комами до числа?


104

У мене є 2,299.00рядок, і я намагаюся розібрати її на число. Я спробував використати parseFloat, що призводить до 2. Я думаю, що проблема з комою, але як би я вирішив це питання правильним способом? Просто зняти кому?

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

Відповіді:


121

Так, видаліть коми:

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

7
Так, але тепер десяткові знаки втрачені. 2300,00, наприклад, 2300.
— користувач1540714

@ user1540714 thats тому, що це поплавок, а не рядок. Якщо вам потрібно вивести його, вам потрібно відформатувати його, щоб завжди відображалися 2 знаки після коми.
— Джон Тейлор

Чи можна цього уникнути? Спробую
— toFixed

38
Чи можу я запропонувати нам замість цього захопити всі коми, використовуючи: .replace(/,/g, '') Цей регекс використовує глобальний gдля заміни всіх.
— gdibble

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. org /

Два найкращі варіанти JS, які я натрапив на це поки що:


4
Не можу повірити, що ще ніхто не підтримав цю відповідь, це єдина фактична відповідь на цій сторінці!
— evilkos

9
Повністю згоден з тим, що в Intl повинен був бути аналог для розбору. Здається очевидним, що людям це знадобиться.
— безкарлосне

Це єдиний систематичний спосіб зробити це. Неможливо досягти цього за допомогою одного підходу для регулярного вирівнювання. Коми та періоди мають різні значення в різних мовах.
— 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

у Франції валюта становить 231 123 413,12
— стакдав

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рядок , щоб додати e, Eі +в список допустимих символів:

str = str.replace(/[^\d\.\-eE+]/g, "");

4
Це не спрацює з від'ємними числами чи числами в наукових позначеннях.
— Аадіт М Шах

1
str = str.replace(/(\d+),(?=\d{3}(\D|$))/g, "$1"); Це те, що я б використовував, але я абсолютно марний в регулярному вираженні, і це те, що я знайшов деякий час назад в якійсь іншій нитці SO.
— Джон Тейлор

@JonTaylor: Ціль тут не полягала в тому, щоб перевірити номер, а просто змусити його працювати parseFloat- що підтвердить його. :-)
— TJ Crowder

що я знаю, наскільки я знаю. Я використовую це для перетворення 1,234,567 і т. Д. В 1234567. Як я вже говорив, хоча я абсолютно марний в регулярному виразі, тому я не міг за все життя сказати вам, що насправді робить lol.
— Джон Тейлор

1
погана ідея видалити знак "-" мінус - отримати зовсім інше число, а також, якщо ви розберете гетерогенні формати, "7.500"! == "7500"
— Серж

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.


Він не вдається для таких цифр, як 1111,11, що, очевидно, англійський формат, але повертає 111111
— Mr. Goferito

Дякую, містере Гоферіто, - вибачте - я зафіксував цю функцію.
— Герфрід

Схоже, це може також не вдатися, наприклад, для дуже малих цифр "0,124" у французькій мові.
— Пол Олександр

Ву, чудово! Це майже точно те, що я шукав: 3,00 €також замінено на 3,00. Просто примітка, яка 3,001відформатована 3001. Щоб цього уникнути, введення завжди має бути з десятковими символами. Наприклад, 3,001.00€ 3,001.00перетворює правильно. Також, будь ласка, оновіть jsfiddle. 0,124Є ще перехід на 124
— Арніс Юрага

молодець, я думаю, що варто відповісти правильним
— Waheed

5

Неприємно, що вони включали toLocaleString, але не метод розбору . Принаймні toLocaleString без аргументів добре підтримується в IE6 +.

Для рішення 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

Якщо ви хочете уникнути проблеми, яку виклав Девід Мейстер, і ви впевнені в кількості десяткових знаків, ви можете замінити всі крапки і коми і розділити на 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 просто поверне 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

Якщо ви хочете відповісти 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, ""));

9
це насправді не відповідь l10n, оскільки для деяких локалів (наприклад, DE) кома є десятковою комою.
— Андреас

А також replace()замінює тільки перший матч , коли не використовується RegExpз 'g'прапором.
— бінкі

@binki Дякую Виправлено.
— Тоні Топпер

@Andreas Це відповідь l10n. Якщо ви хочете іншої валюти, ви просто зміните значення valuId на цю країну valuId.
— Тоні Топпер

1
@TonyTopper це не змінює того факту, що заміна для сепаратора тисяч твердо кодується, ,яка знаходиться в кодовому сепараторі в деяких місцевостях
— Андреас

0

Замініть кому порожнім рядком:

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


це не безпечно. Як вже згадувалося в інших відповідях, у багатьох частинах світу коми ставлять десяткову точку.
— Девід Мейстер

1
Також цей метод не працюватиме на 2299 000,00, оскільки він замінить лише першу
— косу

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 розбиває рядок на масив, використовуючи "," як роздільник і повертає масив.
Функція приєднання приєднується до елементів масиву, поверненого з розбитої функції.
Функція Number () перетворює об'єднаний рядок у число.


Будь ласка, детальніше розкажіть, що таке рішення та як воно вирішує проблему.
— Тарік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.