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


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.