it-roy-ru.com

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

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

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

54
user1540714

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

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

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

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

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

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

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

47
David Meister

Удалите все, что не является цифрой, десятичной точкой или знаком минус (-):

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, "");
26
T.J. Crowder

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

Очевидно, что здесь есть место для некоторой оптимизации и кэширования, но это надежно работает на всех языках.

20
Paul Alexander

Обычно вам следует рассмотреть возможность использования полей ввода, которые не допускают произвольного ввода текста для числовых значений. Но могут быть случаи, когда нужно угадать формат ввода. Например, 1,234,56 в Германии означает 1234,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.

11
Gerfried

Все эти ответы потерпят неудачу, если у вас есть число в миллионах.

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(''));
1
Case

Это сбивает с толку, что они включили toLocaleString но не parse метод. По крайней мере 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, "."));
1
Fábio

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

0
Fernando Limeira

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

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

0
Aadit M Shah

Если у вас есть небольшой набор поддерживаемых локалей, вам, вероятно, будет лучше, просто жестко запрограммировав пару простых правил:

function parseNumber(str, locale) {
  let radix = ',';
  if (locale.match(/(en|th)([-_].+)?/)) {
    radix = '.';
  }
  return Number(str
    .replace(new RegExp('[^\\d\\' + radix + ']', 'g'), '')
    .replace(radix, '.'));
}
0
Andreas Baumgart

Если вы хотите получить ответ, сделайте это так. Пример использует валюту, но вам это не нужно. Библиотека 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, ""));
0
Tony Topper