web-dev-qa-db-ja.com

コンマ千の区切り文字を含む文字列を数値に解析するにはどうすればよいですか?

私は持っています 2,299.00を文字列として、数値に解析しようとしています。 parseFloatを使用してみましたが、結果は2になります。コンマが問題だと思いますが、この問題を正しい方法で解決するにはどうすればよいですか。コンマを削除するだけですか?

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

はい、コンマを削除します。

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

他の人がコメントで言及しているように、多くのロケールではコンマを使用して異なるもの(小数点以下の桁など)を意味するため、コンマを削除することは潜在的に危険です。

どこから文字列を取得したかわかりませんが、世界のいくつかの場所では_"2,299.00"_ = _2.299_

Intlオブジェクトはこの問題に取り組む良い方法かもしれませんが、どういうわけかIntl.NumberFormat.format() AP​​Iのみでparseの対応物なしで仕様を出荷できました:(

文化的な数字を含む文字列をi18nの正しい方法で機械が認識できる数字に解析する唯一の方法は、CLDRデータを活用するライブラリを使用して、数字文字列をフォーマットするあらゆる可能な方法をカバーすることです http:// cldr.unicode.org/

これまでにこれまで出会った2つの最良のJSオプション:

67
David Meister

最新のブラウザでは、組み込みの 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 }`);
}

明らかに最適化とキャッシングの余地がありますが、これはすべての言語で確実に機能します。

27
Paul Alexander

数字、小数点、またはマイナス記号(-)以外のものをすべて削除します。

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行を変更して、eE、および+を受け入れ可能な文字のリストに追加します。

str = str.replace(/[^\d\.\-eE+]/g, "");
24
T.J. Crowder

通常、数値のフリーテキスト入力を許可しない入力フィールドの使用を検討する必要があります。ただし、入力形式を推測する必要がある場合があります。たとえば、ドイツの1.234,56は、米国の1,234.56を意味します。 10進数としてコンマを使用する国のリストについては、 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つの弱点があります。1,123または1.123がある場合、形式を推測することはできません。ロケール形式によっては、両方がコンマまたは3桁区切り文字になる可能性があるためです。この特別な場合、関数はセパレータを千単位のセパレータとして扱い、1123を返します。

12
Gerfried

toLocaleStringメソッドが含まれていたがparseメソッドが含まれていなかったのは不可解です。 IE6 +では、少なくともtoLocaleString引数なしがサポートされています。

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, "."));
4
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(...)を使用できます。

2

これは、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
Adam Jagosz

数百万の数がある場合、これらの答えはすべて失敗します。

3,456,789は、replaceメソッドで単に3456を返します。

カンマを単に削除するための最も正しい答えは、そうでなければならないでしょう。

var number = '3,456,789.12';
number.split(',').join('');
/* number now equips 3456789.12 */
parseFloat(number);

または単に書かれた。

number = parseFloat(number.split(',').join(''));
1
Case

カンマを空の文字列に置き換えます。

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

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, ""));
0
Tony Topper