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


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.