J'ai 2,299.00
comme chaîne et j'essaie de l'analyser en un nombre. J'ai essayé d'utiliser parseFloat
, ce qui donne 2. Je suppose que la virgule est le problème, mais comment pourrais-je résoudre ce problème correctement? Il suffit de retirer la virgule?
var x = parseFloat("2,299.00")
alert(x);
Oui, supprimez les virgules:
parseFloat(yournumber.replace(/,/g, ''));
Supprimer des virgules est potentiellement dangereux car, comme d'autres l'ont mentionné dans les commentaires, de nombreux paramètres régionaux utilisent une virgule pour signifier quelque chose de différent (comme une décimale).
Je ne sais pas d'où vient votre chaîne, mais dans certains endroits du monde "2,299.00"
= 2.299
L'objet Intl
aurait pu être un bon moyen de résoudre ce problème, mais ils ont néanmoins réussi à envoyer la spécification avec uniquement une API Intl.NumberFormat.format()
et aucun homologue parse
:(
Le seul moyen d’analyser une chaîne contenant des caractères numériques culturels en un numéro reconnaissable par une machine consiste à utiliser une bibliothèque qui exploite les données CLDR pour couvrir toutes les méthodes de formatage des chaînes numériques http: // cldr. unicode.org/
Les deux meilleures options JS que j'ai rencontrées jusqu'à présent:
Supprimez tout ce qui n'est pas un chiffre, un point décimal ou un signe moins (-
):
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);
Notez que cela ne fonctionnera pas pour les nombres en notation scientifique. Si vous le souhaitez, modifiez la ligne replace
pour ajouter e
, E
et +
à la liste des caractères acceptés:
str = str.replace(/[^\d\.\-eE+]/g, "");
Sur les navigateurs modernes, vous pouvez utiliser le Intl.NumberFormat intégré pour détecter le formatage du numéro du navigateur et normaliser l'entrée à mettre en correspondance.
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 }`);
}
Leur peut évidemment être optimisé et mis en cache, mais cela fonctionne de manière fiable dans toutes les langues.
En règle générale, vous devriez envisager d'utiliser des champs de saisie qui n'autorisent pas la saisie de texte libre pour les valeurs numériques. Mais il peut y avoir des cas où vous devez deviner le format d'entrée. Par exemple, 1.234.56 en Allemagne signifie 1.234.56 aux États-Unis. Voir https://salesforce.stackexchange.com/a/21404 pour obtenir une liste des pays qui utilisent des virgules comme décimales.
J'utilise la fonction suivante pour faire une meilleure estimation et supprimer tous les caractères non numériques:
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);
}
Essayez-le ici: https://plnkr.co/edit/9p5Y6H?p=preview
Exemples:
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
La fonction a un point faible: il est impossible de deviner le format si vous avez 1 123 ou 1,123 - car, en fonction du format de la langue, les deux peuvent être une virgule ou un séparateur de milliers. Dans ce cas particulier, la fonction traitera le séparateur comme un séparateur de milliers et renverra 1123.
C'est un wrapper simpliste et simpliste autour de la fonction 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);
}
Toutes ces réponses échouent si vous avez un nombre de millions.
3 356 789 renverraient simplement 3456 avec la méthode replace.
La réponse la plus correcte pour supprimer simplement les virgules devrait être.
var number = '3,456,789.12';
number.split(',').join('');
/* number now equips 3456789.12 */
parseFloat(number);
Ou simplement écrit.
number = parseFloat(number.split(',').join(''));
Il est étonnant qu'ils aient inclus une méthode toLocaleString mais pas une méthode parse . Au moins toLocaleString sans arguments est bien pris en charge dans IE6 +.
Pour une solution i18n , je suis venu avec ceci:
Commencez par détecter le séparateur décimal des paramètres régionaux de l'utilisateur:
var decimalSeparator = 1.1;
decimalSeparator = decimalSeparator.toLocaleString().substring(1, 2);
Puis normalisez le nombre s'il y a plus d'un séparateur décimal dans la chaîne:
var pattern = "([" + decimalSeparator + "])(?=.*\\1)";separator
var formatted = valor.replace(new RegExp(pattern, "g"), "");
Enfin, supprimez tout ce qui n'est pas un nombre ou un séparateur décimal:
formatted = formatted.replace(new RegExp("[^0-9" + decimalSeparator + "]", "g"), '');
return Number(formatted.replace(decimalSeparator, "."));
Si vous voulez éviter le problème publié par David Meister et que vous êtes certain du nombre de décimales, vous pouvez remplacer tous les points et les virgules et le diviser par 100, ex .:
var value = "2,299.00";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/100;
ou si vous avez 3 décimales
var value = "2,299.001";
var amount = parseFloat(value.replace(/"|\,|\./g, ''))/1000;
C'est à vous de décider si vous souhaitez utiliser parseInt, parseFloat ou Number. Aussi, si vous souhaitez conserver le nombre de décimales, vous pouvez utiliser la fonction .toFixed (...).
Remplacez la virgule par une chaîne vide:
var x = parseFloat("2,299.00".replace(",",""))
alert(x);
Si vous avez un petit nombre de paramètres régionaux à prendre en charge, il serait probablement préférable de coder en dur quelques règles simples:
function parseNumber(str, locale) {
let radix = ',';
if (locale.match(/(en|th)([-_].+)?/)) {
radix = '.';
}
return Number(str
.replace(new RegExp('[^\\d\\' + radix + ']', 'g'), '')
.replace(radix, '.'));
}
Si vous voulez une réponse, faites-le de cette façon. L'exemple utilise la monnaie, mais vous n'en avez pas besoin. La bibliothèque Intl devra être remplie si vous devez supporter les navigateurs plus anciens.
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, ""));