Как мне преобразовать строку с разделителем тысяч запятую в число?


107

У меня 2,299.00есть строка, и я пытаюсь разобрать ее на число. Я пробовал использовать parseFloat, что дало 2. Думаю, проблема в запятой, но как мне решить эту проблему правильно? Просто убрать запятую?

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

Ответы:


121

Да удалите запятые:

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

7
Да, но теперь десятичные знаки потеряны. Например, 2300.00 дает 2300.
— user1540714

@ user1540714 потому что это число с плавающей запятой, а не строка. Если вам нужно вывести его, вам нужно отформатировать его, чтобы всегда отображать 2 десятичных знака.
— Jon Taylor

38
Могу я предложить вместо этого захватить все запятые с помощью: .replace(/,/g, '') Это регулярное выражение использует глобальное значение gдля замены-все.
— gdibble

33
Понятия не имею, почему этот ответ получил так много голосов и был выбран как правильный, у него есть две серьезные проблемы. 1. Он не может обрабатывать числа с несколькими запятыми, например, parseFloat("2,000,000.00".replace(',',''))возвращает 2000и 2. Он не работает во многих регионах мира, где ,используется десятичный разряд, например, parseFloat("2.000.000,00".replace(',',''))возвращает 2- см. Мой ответ ниже о том, что работает повсюду в мире.
— Дэвид Мейстер

1
Во французском языке запятая является десятичным разделителем ... Таким образом, это не подходит для очень вероятного сценария, когда браузер установил французский язык
— Сайед Акил Ашик

115

Удаление запятых потенциально опасно, потому что, как другие упоминали в комментариях, во многих регионах запятая используется для обозначения чего-то другого (например, десятичного знака).

Я не знаю, откуда у вас строка, но в некоторых местах в мире "2,299.00"=2.299

IntlОбъект мог бы быть хороший способ решить эту проблему, но каким - то образом им удалось отправить спецификацию с только Intl.NumberFormat.format()API и не parseаналог :(

Единственный способ разобрать строку с культурными числовыми символами в ней до распознаваемого машиной числа любым разумным способом i18n - это использовать библиотеку, которая использует данные CLDR, чтобы охватить все возможные способы форматирования числовых строк http: //cldr.unicode. org /

Два лучших варианта JS, с которыми я сталкивался на данный момент:


4
Не могу поверить, что никто еще не поддержал этот ответ, это единственный реальный ответ на этой странице!
— Evilkos 08

9
Полностью согласен, что у Intl должен был быть аналог для синтаксического анализа. Кажется очевидным, что это понадобится людям.
— Carlossless

Это единственный систематический способ сделать это. Этого нельзя добиться с помощью одного универсального подхода к регулярному выражению. Запятые и точки имеют разное значение в разных языках.
— Wildhammer

39

В современных браузерах вы можете использовать встроенный 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
— stackdave

Если вам нужна поддержка IE11, замените 3-ю строку на: const cleanPattern = new RegExp("[^-+0-9" + example.charAt( 1 ) + "]", 'g');- строки шаблона "` "не поддерживаются IE - caniuse.com/#search=template%20string
— long

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
Это не сработает для отрицательных чисел или чисел в научном представлении.
— Aadit M Shah

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

@JonTaylor: Целью здесь было не проверить номер, а просто заставить его работать parseFloat- что подтвердит его. :-)
— TJ Crowder

что мой действительно делает, насколько я знаю. Я использую это, чтобы преобразовать 1,234,567 и т. Д. В 1234567. Как я уже сказал, я совершенно бесполезен в регулярных выражениях, поэтому я не мог, хоть убей, сказать вам, что это на самом деле делает lol.
— Jon Taylor

1
плохая идея удалить знак минус «-» - получить совершенно другое число, а также, если вы разбираете разнородные форматы, «7.500»! == «7,500»
— Serge

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.


Он не работает с числами вроде 1,111,11, что явно является английским форматом, но возвращает 111111
— Мистер Гоферито

Спасибо, мистер Гоферито - извините - я исправил функцию.
— Gerfried

Похоже, это также может не сработать, например, для очень маленьких чисел «0,124» во французском языке.
— Paul Alexander

Ой, отлично! Это практически то, что я искал: 3,00 €тоже заменено на 3.00. Просто примечание, 3,001отформатированное в 3001. Чтобы этого избежать, всегда вводите десятичные символы. Напр. 3,001.00€ 3,001.00Конвертирует правильно. Также обновите jsfiddle. 0,124там еще конвертируется в 124
— Арнис Джурага

молодец, приятель, я думаю, стоит быть правильным ответом
— Вахид

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 с помощью метода replace.

Самый правильный ответ для простого удаления запятых должен быть.

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

С помощью этой функции вы сможете форматировать значения в нескольких форматах, таких как 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

Если вы хотите получить ответ, сделайте это так. В примере используется валюта, но она вам не нужна. Библиотеку 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
это не совсем правильный ответ, потому что для некоторых языков (например, DE) запятая является десятичной точкой.
— Андреас

А также replace()заменяет только первое совпадение, если не используется RegExpс 'g'флагом.
— binki

@binki Спасибо. Исправлена.
— Тони Топпер

@Andreas Это l10n ответ. Если вам нужна другая валюта, вы просто измените значение currencyId на currencyId этой страны.
— Тони Топпер

1
@TonyTopper, это не меняет того факта, что замена разделителя тысяч жестко запрограммирована, ,что в некоторых регионах находится в разделителе запятой
— Андреас

0

Замените запятую пустой строкой:

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


это небезопасно. Как упоминалось в других ответах, во многих частях мира запятые представляют собой десятичную точку.
— Дэвид Мейстер

1
Также этот метод не будет работать на 2,299,000.00, так как он заменит только первую запятую
— wizulus

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

Функция split разбивает строку на массив, используя "," в качестве разделителя, и возвращает массив.
Функция соединения объединяет элементы массива, возвращаемого функцией разделения.
Функция Number () преобразует объединенную строку в число.


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