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

107

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

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

user1540714
источник

Ответы:

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, "");
TJ Crowder
источник
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"
Joseantgv
источник
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 () преобразует объединенную строку в число.

Бруно
источник
Пожалуйста, расскажите немного подробнее о том, каково решение и как оно решает проблему.
Тарик