Wie kann ich eine Zeichenfolge mit einem Komma-Tausender-Trennzeichen zu einer Zahl analysieren?

103

Ich habe 2,299.00als Zeichenfolge und ich versuche, es auf eine Zahl zu analysieren. Ich habe versucht, zu verwenden parseFloat, was zu 2 führt. Ich denke, das Komma ist das Problem, aber wie würde ich dieses Problem richtig lösen? Komma einfach entfernen?

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

user1540714
quelle

Antworten:

121

Ja, entfernen Sie die Kommas:

parseFloat(yournumber.replace(/,/g, ''));
Sam
quelle
7
Ja, aber jetzt gehen die Dezimalstellen verloren. 2300.00 ergibt zum Beispiel 2300.
Benutzer1540714
@ user1540714 Das liegt daran, dass es eher ein Float als ein String ist. Wenn Sie es dann ausgeben müssen, müssen Sie es so formatieren, dass immer 2 Dezimalstellen angezeigt werden.
Jon Taylor
Kann das vermieden werden? Ich versuche toFixed
user1540714
38
Darf ich vorschlagen, dass wir stattdessen alle Kommas erfassen, indem wir .replace(/,/g, '') Folgendes verwenden : Dieser reguläre Ausdruck verwendet das Globale g, um alle zu ersetzen.
gdibble
32
Ich habe keine Ahnung, warum diese Antwort so viele positive Stimmen erhalten hat und als richtig ausgewählt wurde. Sie hat zwei schwerwiegende Probleme. 1. Es kann keine Zahlen mit mehreren Kommas verarbeiten, z. B. parseFloat("2,000,000.00".replace(',',''))Rückgaben, 2000und 2. es schlägt in vielen Regionen der Welt fehl, in denen ,es sich um eine Dezimalstelle handelt, z. B. parseFloat("2.000.000,00".replace(',',''))Rückgaben 2- siehe meine Antwort unten für etwas, das überall auf der Welt funktioniert.
David Meister
113

Das Entfernen von Kommas ist möglicherweise gefährlich, da viele Gebietsschemas, wie andere in den Kommentaren erwähnt haben, ein Komma verwenden, um etwas anderes zu bedeuten (z. B. eine Dezimalstelle).

Ich weiß nicht, woher du deine Saite hast, aber an einigen Orten auf der Welt "2,299.00"=2.299

Das IntlObjekt hätte ein guter Weg sein können, um dieses Problem anzugehen, aber irgendwie gelang es ihnen, die Spezifikation nur mit einer Intl.NumberFormat.format()API und ohne parseGegenstück zu versenden :(

Die einzige Möglichkeit, eine Zeichenfolge mit darin enthaltenen kulturellen numerischen Zeichen auf eine vernünftige Weise in eine maschinenerkennbare Zahl zu analysieren, besteht darin, eine Bibliothek zu verwenden, die CLDR-Daten nutzt, um alle Möglichkeiten zur Formatierung von Zahlenzeichenfolgen abzudecken. Http: //cldr.unicode. org /

Die zwei besten JS-Optionen, die mir bisher begegnet sind:

David Meister
quelle
4
Ich kann nicht glauben, dass noch niemand diese Antwort positiv bewertet hat. Es ist die einzige tatsächliche Antwort auf dieser Seite!
Evilkos
9
Stimmen Sie voll und ganz zu, dass Intl ein Parsing-Gegenstück hätte haben sollen. Es scheint offensichtlich, dass die Leute dies brauchen würden.
carlossless
Dies ist der einzige systematische Weg, dies zu tun. Dies kann nicht mit einem Regex-Fits-All-Ansatz erreicht werden. Kommas und Punkte haben in verschiedenen Sprachen unterschiedliche Bedeutungen.
Wildhammer
38

In modernen Browsern können Sie das integrierte Intl.NumberFormat verwenden , um die Zahlenformatierung des Browsers zu erkennen und die Eingabe entsprechend zu normalisieren.

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 }`);
}

Es gibt offensichtlich Raum für Optimierungen und Caching, aber dies funktioniert zuverlässig in allen Sprachen.

Paul Alexander
quelle
Warum hat das nicht eine Menge Upvotes bekommen !!! Es ist die eleganteste Lösung für INPUT in internationalen Formaten! Danke dir!!
Kpollock
in Frankreich Währung ist 231 123 413,12
Stackdave
26

Entfernen Sie alles, was keine Ziffer, kein Dezimalpunkt oder Minuszeichen ist ( -):

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

Geige aktualisiert

Beachten Sie, dass es für Zahlen in wissenschaftlicher Notation nicht funktioniert. Wenn Sie es wollen , die ändern replaceZeile hinzufügen e, Eund +auf die Liste der zulässigen Zeichen:

str = str.replace(/[^\d\.\-eE+]/g, "");
TJ Crowder
quelle
4
Dies funktioniert nicht für negative Zahlen oder Zahlen in wissenschaftlicher Notation.
Aadit M Shah
1
str = str.replace(/(\d+),(?=\d{3}(\D|$))/g, "$1"); Dies ist, was ich verwenden würde, aber ich bin bei Regex völlig nutzlos und etwas, das ich vor einiger Zeit in einem anderen SO-Thread gefunden habe.
Jon Taylor
@ JonTaylor: Das Ziel hier war nicht, die Nummer zu validieren , sondern nur dafür zu sorgen, dass sie funktioniert parseFloat- was sie validiert. :-)
TJ Crowder
was meins tut, soweit ich weiß. Ich verwende dies, um 1.234.567 usw. in 1234567 umzuwandeln. Wie gesagt, obwohl ich bei Regex völlig nutzlos bin, konnte ich Ihnen für mein ganzes Leben nicht sagen, was es tatsächlich tut, lol.
Jon Taylor
1
schlechte Idee, "-" Minuszeichen zu entfernen - erhalten Sie eine völlig andere Zahl, und auch wenn Sie heterogene Formate analysieren, "7.500"! == "7.500"
Serge
14

Normalerweise sollten Sie Eingabefelder verwenden, die keine Freitexteingabe für numerische Werte zulassen. Es kann jedoch Fälle geben, in denen Sie das Eingabeformat erraten müssen. Zum Beispiel bedeutet 1,234,56 in Deutschland 1.234,56 in den USA. Unter https://salesforce.stackexchange.com/a/21404 finden Sie eine Liste der Länder, die Komma als Dezimalzahl verwenden.

Ich benutze die folgende Funktion, um eine bestmögliche Vermutung anzustellen und alle nicht numerischen Zeichen zu entfernen:

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);
}   

Probieren Sie es hier aus: https://plnkr.co/edit/9p5Y6H?p=preview

Beispiele:

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

Die Funktion hat eine Schwachstelle: Es ist nicht möglich, das Format zu erraten, wenn Sie 1.123 oder 1.123 haben - da je nach Gebietsschema-Format beide ein Komma oder ein Tausendertrennzeichen sein können. In diesem speziellen Fall behandelt die Funktion das Trennzeichen als Tausendertrennzeichen und gibt 1123 zurück.

Gerfried
quelle
Es schlägt fehl für Zahlen wie 1.111,11, die offensichtlich englisches Format ist, aber 111111
Mr. Goferito
Vielen Dank, Herr Goferito - es tut mir leid - ich habe die Funktion behoben.
Gerfried
Sieht so aus, als könnte dies auch bei sehr kleinen Zahlen "0,124" im französischen Gebietsschema fehlschlagen.
Paul Alexander
Wou, großartig! Das ist fast genau das, wonach ich gesucht habe: wird 3,00 €auch auf 3.00 ersetzt. Nur eine Notiz, die 3,001formatiert ist 3001. Um dies zu vermeiden, sollte die Eingabe immer mit Dezimalsymbolen erfolgen. ZB 3,001.00€ 3,001.00konvertiert richtig. Bitte aktualisieren Sie auch jsfiddle. 0,124Es ist immer noch zu 124 konvertiert
Arnis Juraga
Gut gemacht Kumpel, ich denke, es lohnt sich, die richtige Antwort zu sein
Waheed
5

Es ist rätselhaft , dass sie eine inbegriffen toLocaleString aber keine Parse - Methode. Zumindest toLocaleString ohne Argumente wird in IE6 + gut unterstützt.

Für eine i18n- Lösung habe ich Folgendes entwickelt:

Ermitteln Sie zuerst das Dezimaltrennzeichen für das Gebietsschema des Benutzers:

var decimalSeparator = 1.1;
decimalSeparator = decimalSeparator.toLocaleString().substring(1, 2);

Normalisieren Sie dann die Zahl, wenn der String mehr als ein Dezimaltrennzeichen enthält:

var pattern = "([" + decimalSeparator + "])(?=.*\\1)";separator
var formatted = valor.replace(new RegExp(pattern, "g"), "");

Entfernen Sie zum Schluss alles, was keine Zahl oder kein Dezimaltrennzeichen ist:

formatted = formatted.replace(new RegExp("[^0-9" + decimalSeparator + "]", "g"), '');
return Number(formatted.replace(decimalSeparator, "."));
Fábio
quelle
5

Dies ist ein einfacher, unauffälliger Wrapper um die parseFloatFunktion.

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);
}
Adam Jagosz
quelle
2

Wenn Sie das von David Meister gepostete Problem vermeiden möchten und sich über die Anzahl der Dezimalstellen sicher sind, können Sie alle Punkte und Kommas ersetzen und durch 100 teilen, z.

var value = "2,299.00";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/100;

oder wenn Sie 3 Dezimalstellen haben

var value = "2,299.001";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/1000;

Es liegt an Ihnen, ob Sie parseInt, parseFloat oder Number verwenden möchten. Wenn Sie die Anzahl der Dezimalstellen beibehalten möchten, können Sie die Funktion .toFixed (...) verwenden.

Fernando Limeira
quelle
1

Alle diese Antworten schlagen fehl, wenn Sie eine Zahl in Millionenhöhe haben.

3.456.789 würden einfach 3456 mit der Ersetzungsmethode zurückgeben.

Die richtigste Antwort zum einfachen Entfernen der Kommas müsste sein.

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

Oder einfach geschrieben.

number = parseFloat(number.split(',').join(''));
Fall
quelle
Natürlich verwenden Amerikaner Komma und nicht Punkt. Es wäre dumm zu versuchen, eine Monstrosität zu schaffen, um mit beiden fertig zu werden.
Fall
2
Eine solche "Monstrosität" existiert jedoch bereits als Teil dessen, was Unicode bietet (siehe meine Antwort). Ich bin sicher, Sie würden sich weniger dumm fühlen, wenn Sie ein Unternehmen mit internationalen Kunden führen würden.
David Meister
1

Dadurch wird eine Nummer in einem beliebigen Gebietsschema in eine normale Nummer konvertiert. Funktioniert auch für Dezimalstellen:

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
Eldar Gerfanov
quelle
1

Mit dieser Funktion können Sie Werte in verschiedenen Formaten wie 1.234,56und 1,234.56und sogar mit Fehlern wie 1.234.56und formatieren1,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
quelle
0

Wenn Sie eine l10n-Antwort wünschen, tun Sie dies auf diese Weise. Beispiel verwendet Währung, aber das brauchen Sie nicht. Die internationale Bibliothek muss mehrfach gefüllt sein, wenn Sie ältere Browser unterstützen müssen.

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, ""));
Tony Topper
quelle
9
Dies ist keine wirkliche Antwort, da für einige Gebietsschemas (z. B. DE) das Komma der Dezimalpunkt ist.
Andreas
Und ersetzt auch replace()nur das erste Match, wenn es nicht RegExpmit 'g'Flag verwendet wird.
Binki
@binki Danke. Fest.
Tony Topper
@Andreas Dies ist die l10n Antwort. Wenn Sie eine andere Währung möchten, ändern Sie einfach den Wert vonrencyId in die CurrencyId dieses Landes.
Tony Topper
1
@ TonyTopper Dies ändert nichts an der Tatsache, dass der Ersatz für das Tausendertrennzeichen fest ,codiert ist, der in einigen Regionen im Komma- Trennzeichen steht
Andreas
0

Ersetzen Sie das Komma durch eine leere Zeichenfolge:

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

Aadit M Shah
quelle
das ist nicht sicher. Wie in anderen Antworten erwähnt, stellen Kommas in vielen Teilen der Welt einen Dezimalpunkt dar.
David Meister
1
Auch diese Methode würde bei 2.299.000,00 nicht funktionieren, da sie nur das erste Komma ersetzen würde
Wizulus
0

Wenn Sie eine kleine Anzahl von Gebietsschemas unterstützen möchten, sind Sie wahrscheinlich besser dran, wenn Sie nur ein paar einfache Regeln fest codieren:

function parseNumber(str, locale) {
  let radix = ',';
  if (locale.match(/(en|th)([-_].+)?/)) {
    radix = '.';
  }
  return Number(str
    .replace(new RegExp('[^\\d\\' + radix + ']', 'g'), '')
    .replace(radix, '.'));
}
Andreas Baumgart
quelle
0
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, '.'));
};
Denys Rusov
quelle
0
Number("2,299.00".split(',').join(''));   // 2299

Die Split-Funktion teilt die Zeichenfolge mit "," als Trennzeichen in ein Array auf und gibt ein Array zurück.
Die Join-Funktion verbindet die Elemente des Arrays, die von der Split-Funktion zurückgegeben werden.
Die Funktion Number () konvertiert die verknüpfte Zeichenfolge in eine Zahl.

Bruno
quelle
Bitte erläutern Sie etwas genauer, was die Lösung ist und wie sie das Problem löst.
Tariq