Supprimer les zéros de fin insignifiants d'un nombre?

157

Ai-je manqué un appel d'API standard qui supprime les zéros insignifiants de fin d'un nombre?

Ex.

var x = 1.234000 // to become 1.234;
var y = 1.234001; // stays 1.234001

Number.toFixed () et Number.toPrecision () ne sont pas tout à fait ce que je recherche.

Steven
la source
6
Um, 1.234000 === 1.234.
Gumbo
5
Oui, si vous faites une alerte (x), il apparaît sans les zéros de fin
JKirchartz
50
Après avoir travaillé avec un certain nombre de clients, je peux témoigner que même si 1.234000 === 1.234, les clients ne veulent pas voir ces zéros supplémentaires s'ils n'en ont pas besoin.
contactmatt
16
Utiliser parseFloat(n)?
Mr. Alien
C'était la solution la plus simple qui couvrait tous les cas extrêmes pour moi, merci @ Mr.Alien.
James

Réponses:

140

Si vous le convertissez en chaîne, il n'affichera pas de zéros à la fin, qui ne sont pas stockés dans la variable en premier lieu car il a été créé en tant que nombre, pas en tant que chaîne.

var n = 1.245000
var noZeroes = n.toString() // "1.245" 
Cristian Sanchez
la source
6
J'étais sur le point de publier du code pour supprimer les zéros mais la solution de Daniel semble fonctionner. Cela fonctionne même pour des chaînes telles que "1.2345000". ("1.2345000" * 1) .toString (); // devient 1.2345
Steven
7
Bien sûr, si votre var est déjà une chaîne, vous devez d'abord la convertir en nombre, puis à nouveau
derekcohen
Cela a très bien fonctionné. J'avais le même problème, converti le flotteur en chaîne, puis parseFloat pour le récupérer dans le bon format, uniquement sans les zéros de fin.
Matt West
10
Ce n'est pas une solution complète. Il ne fonctionne pas lorsque vous avez variable une erreur de représentation à virgule flottante, comme: var n = 1.245000000000001( en supposant qu'il est insignifiant pour être représenté à l' utilisateur)
augurer
7
Peut produire des résultats inattendus pour des nombres comme: 123111111111111111111111111111122222222222222222222222222222222222222222222222.00. La représentation sous forme de chaîne sera au format exponentiel: 1.231111111111111e + 81
Stas Makutin
227

J'avais une instance similaire où je voulais utiliser .toFixed()si nécessaire, mais je ne voulais pas le rembourrage quand ce n'était pas le cas. J'ai donc fini par utiliser parseFloat en conjonction avec toFixed.

toFixed sans rembourrage

parseFloat(n.toFixed(4));

Une autre option qui fait presque la même chose
Cette réponse peut vous aider dans votre décision

Number(n.toFixed(4));

toFixedarrondira / complétera le nombre à une longueur spécifique, mais le convertira également en chaîne. La reconversion en un type numérique rendra non seulement le nombre plus sûr à utiliser arithmétiquement, mais supprimera également automatiquement tous les 0 à la fin. Par exemple:

var n = "1.234000";
    n = parseFloat(n);
 // n is 1.234 and in number form

Parce que même si vous définissez un nombre avec des zéros à la fin, ils sont supprimés.

var n = 1.23000;
 // n == 1.23;
Gary
la source
Notez que cela ne fonctionne que si le nombre approprié de décimales est égal ou supérieur à l'argument toFixed. Si le nombre est par exemple 1.200000, le résultat de toFixed (3) sera 1.200 et donc, tous les zéros de fin ne seront pas supprimés.
Leopoldo Sanczyk
@LeopoldoSanczyk Non, ce n'est vrai que si vous utilisez simplement toFixed, car il renvoie une chaîne. Les types de nombres perdent automatiquement les zéros de fin. C'est pourquoi j'ai utilisé les deux en tandem.
Gary
@Gary, je retire mon commentaire, j'ai vu parseFloat(n).toFixed(4);au lieu de votre réponse réelle. Je suis désolé.
Leopoldo Sanczyk
2
Pourquoi pas +(n.toFixed(4))?
Константин Ван
3
voté! un seul problème avec votre réponse 0,00000005 est converti en 5e-8 comment puis-je supprimer les zéros insignifiants sans ce problème, je travaille avec de petits nombres tels que 0,000058000 où les zéros à la fin doivent être supprimés
PirateApp
29

J'ai d'abord utilisé une combinaison de matti-lyra et de réponses de Gary:

r=(+n).toFixed(4).replace(/\.0+$/,'')

Résultats:

  • 1234870.98762341: "1234870.9876"
  • 1230009100: "1230009100"
  • 0,0012234: "0,0012"
  • 0.1200234: "0.12"
  • 0,000001231: "0"
  • 0,10001: «0,1000»
  • "asdf": "NaN" (donc pas d'erreur d'exécution)

Le cas quelque peu problématique est 0,10001. J'ai fini par utiliser cette version plus longue:

    r = (+n).toFixed(4);
    if (r.match(/\./)) {
      r = r.replace(/\.?0+$/, '');
    }
  • 1234870.98762341: "1234870.9876"
  • 1230009100: "1230009100"
  • 0,0012234: "0,0012"
  • 0.1200234: "0.12"
  • 0,000001231: "0"
  • 0,10001: «0,1»
  • "asdf": "NaN" (donc pas d'erreur d'exécution)

Mise à jour : Et voici la version la plus récente de Gary (voir les commentaires):

r=(+n).toFixed(4).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/,'$1')

Cela donne les mêmes résultats que ci-dessus.

w00t
la source
1
J'ai une solution pure regex qui, je crois, fonctionnetoFixed(4).replace(/([0-9]+(\.[1-9]+)?)(\.?0+$)/,"$1")
Gary
1
Gah! Apparemment, je ne suis pas aussi doué pour briser mes propres RegEx que d'autres. Je ne laisserai pas cela me battre! J'ai couru celui-ci contre tous vos cas de test plus n'importe quel (valide) auquel je pourrais penser([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)
Gary
1
Le regex est gourmand et supprime parfois un "0" de la partie entière! :-( Pourquoi pas juste replace(/[,.][1-9]+(0+)/,'')?
Sebastian Sebald
1
Réponse sous-estimée à cela.
Charlie
1
@ w00t Oh, désolé, je comprends maintenant. J'étais la façon dont j'ai testé quand j'ai fait le mien (voir lien ci-dessus). Le vôtre n'échoue pas lorsque vous utilisez toFixed, car le nombre est garanti d'avoir un point, mais il a échoué dans mes tests parce que je voulais que l'expression régulière fonctionne pour n'importe quel nombre, y compris les entiers sans point. Sans toFixed, il mange un zéro à la fin. Ma faute.
geekley
22

La toFixedméthode effectuera l'arrondi approprié si nécessaire. Il ajoutera également des zéros de fin, ce qui n'est pas toujours idéal.

(4.55555).toFixed(2);
//-> "4.56"

(4).toFixed(2);
//-> "4.00"

Si vous convertissez la valeur de retour en un nombre, ces zéros de fin seront supprimés. C'est une approche plus simple que de faire vos propres calculs d'arrondi ou de troncature.

+(4.55555).toFixed(2);
//-> 4.56

+(4).toFixed(2);
//-> 4
CJ
la source
1
délicat, mais exactement ce que je cherchais: supprimer les zéros de fin significatifs (ce que nous avons bien sûr rendu significatif grâce à l' toFixedappel). c'est un cas de bord UX étrange.
worc
12

J'avais fondamentalement la même exigence et j'ai constaté qu'il n'y avait pas de mécanisme intégré pour cette fonctionnalité.

En plus de couper les zéros de fin, j'ai également eu besoin d'arrondir et de formater la sortie pour les paramètres régionaux actuels de l'utilisateur (c'est-à-dire 123 456 789).

Tout mon travail à ce sujet a été inclus sous le nom prettyFloat.js (sous licence MIT) sur GitHub: https://github.com/dperish/prettyFloat.js


Exemples d'utilisation:

prettyFloat(1.111001, 3) // "1.111"
prettyFloat(1.111001, 4) // "1.111"
prettyFloat(1.1111001, 5) // "1.1111"
prettyFloat(1234.5678, 2) // "1234.57"
prettyFloat(1234.5678, 2, true) // "1,234.57" (en-us)


Mise à jour - août 2018


Tous les navigateurs modernes prennent désormais en charge l' API ECMAScript Internationalization , qui fournit une comparaison de chaînes sensible à la langue, la mise en forme des nombres et la mise en forme de la date et de l'heure.

let formatters = {
    default: new Intl.NumberFormat(),
    currency: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 0 }),
    whole: new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0 }),
    oneDecimal: new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 1, maximumFractionDigits: 1 }),
    twoDecimal: new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2 })
};

formatters.twoDecimal.format(1234.5678);  // result: "1,234.57"
formatters.currency.format(28761232.291); // result: "$28,761,232"

Pour les navigateurs plus anciens, vous pouvez utiliser ce polyfill: https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en

dperish
la source
C'est ce que nous recherchions. Vous devez créer un package npm.
EnZo
Je devrais donc probablement mettre à jour cela, car cela est maintenant possible via l'API d'internationalisation.
dperish
2
Ceci est très utile, merci pour le partage et merci pour la mise à jour également.
jaggedsoft
11

Pourquoi ne pas multiplier par un comme ça?

var x = 1.234000*1; // becomes 1.234

var y = 1.234001*1; // stays as 1.234001
Howard
la source
9

Vous pouvez essayer celui-ci pour réduire les nombres flottants

var n = 0.0000;
n = parseFloat(n.toString()); 

//output n = 0; 
// n = 3.14000; --> n = 3.14;
Amit Panasara
la source
7

Réponse pure regex

n.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1');

Je me demande pourquoi personne n'en a donné!

João Costa
la source
Cela ne fonctionnera pas avec les nombres (les nombres sont indiqués dans la question originale). J'adore la solution pour une représentation sous forme de chaîne!
BennyHilarious
6

J'avais également besoin de résoudre ce problème lorsque Django affichait des valeurs de type décimal dans un champ de texte. Par exemple, lorsque «1» était la valeur. Il afficherait «1.00000000». Si '1.23' était la valeur, il afficherait '1.23000000' (dans le cas d'un paramètre 'decimal_places' de 8)

Utiliser parseFloat n'était pas une option pour moi car il est possible qu'il ne renvoie pas exactement la même valeur. toFixed n'était pas une option car je ne voulais rien arrondir, j'ai donc créé une fonction:

function removeTrailingZeros(value) {
    value = value.toString();

    # if not containing a dot, we do not need to do anything
    if (value.indexOf('.') === -1) {
        return value;
    }

    # as long as the last character is a 0 or a dot, remove it
    while((value.slice(-1) === '0' || value.slice(-1) === '.') && value.indexOf('.') !== -1) {
        value = value.substr(0, value.length - 1);
    }
    return value;
}
megasnort
la source
Cela fonctionne, mais c'est assez inefficace, car cela entraîne la création de plusieurs chaînes par exécution. Imaginez l'exécuter sur toutes les cellules d'un tableau, où un bon nombre était de 0,00000. Une meilleure option serait de déterminer le nombre de zéros de fin, puis de découper en une seule fois. Déterminer ce qu'est un caractère est largement efficace, le fractionnement des chaînes l'est moins.
Derek Nigel Bartram
J'ai fait quelque chose de similaire à votre suggestion Derek: github.com/rek/remove-trailing-zeros/blob/master/…
rekarnar
Le test de performance est ici: jsperf.com/remove-trailing-zeros/1 , vous aviez raison, trouver les zéros et les supprimer est bien plus rapide!
rekarnar
4

Aucune de ces solutions n'a fonctionné pour moi pour de très petits nombres. http://numeraljs.com/ a résolu cela pour moi.

parseFloat(0.00000001.toFixed(8));
// 1e-8

numeral(0.00000001).format('0[.][00000000]');
// "0.00000001"
Devon
la source
Il ne peut pas gérer plus de 6 précision. Je dirais que cette bibliothèque est inutile si elle est destinée à de petits nombres. Certainement pas recommandé.
Daniel Kmak
2

Si vous ne pouvez pas utiliser les flottants pour une raison quelconque (comme les flotteurs d'argent impliqués) et que vous commencez déjà à partir d'une chaîne représentant un nombre correct, vous pouvez trouver cette solution pratique. Il convertit une chaîne représentant un nombre en une chaîne représentant un nombre sans zéros de fin.

function removeTrailingZeroes( strAmount ) {
    // remove all trailing zeroes in the decimal part
    var strDecSepCd = '.'; // decimal separator
    var iDSPosition = strAmount.indexOf( strDecSepCd ); // decimal separator positions
    if ( iDSPosition !== -1 ) {
        var strDecPart = strAmount.substr( iDSPosition ); // including the decimal separator

        var i = strDecPart.length - 1;
        for ( ; i >= 0 ; i-- ) {
            if ( strDecPart.charAt(i) !== '0') {
                break;
            }
        }

        if ( i=== 0 ) {
            return strAmount.substring(0, iDSPosition);
        } else {
            // return INTPART and DS + DECPART including the rightmost significant number
            return strAmount.substring(0, iDSPosition) + strDecPart.substring(0,i + 1);
        }
    }

    return strAmount;
}
BennyHilarant
la source
0

Après avoir lu toutes les réponses - et commentaires - je me suis retrouvé avec ceci:

function isFloat(n) {
    let number = (Number(n) === n && n % 1 !== 0) ? eval(parseFloat(n)) : n;
    return number;
}

Je sais que l'utilisation evalpeut être nuisible d'une manière ou d'une autre, mais cela m'a beaucoup aidé.

Alors:

isFloat(1.234000);     // = 1.234;
isFloat(1.234001);     // = 1.234001
isFloat(1.2340010000); // = 1.234001

Si vous souhaitez limiter les décimales, utilisez toFixed()comme d'autres l'ont indiqué.

let number = (Number(n) === n && n % 1 !== 0) ? eval(parseFloat(n).toFixed(3)) : n;

C'est tout.

ed1nh0
la source
0

J'avais besoin de supprimer tous les zéros de fin, mais gardez au moins 2 décimales, y compris les zéros.
Les nombres avec lesquels je travaille sont 6 chaînes de nombres décimaux, générées par .toFixed (6).

Résultat attendu:

var numstra = 12345.000010 // should return 12345.00001
var numstrb = 12345.100000 // should return 12345.10
var numstrc = 12345.000000 // should return 12345.00
var numstrd = 12345.123000 // should return 12345.123

Solution:

var numstr = 12345.100000

while (numstr[numstr.length-1] === "0") {           
    numstr = numstr.slice(0, -1)
    if (numstr[numstr.length-1] !== "0") {break;}
    if (numstr[numstr.length-3] === ".") {break;}
}

console.log(numstr) // 12345.10

Logique:

Exécutez la fonction de boucle si le dernier caractère de la chaîne est un zéro.
Supprimez le dernier caractère et mettez à jour la variable chaîne.
Si le dernier caractère de la chaîne mise à jour n'est pas un zéro, terminer la boucle.
Si la chaîne mise à jour du troisième au dernier caractère est une virgule flottante, terminer la boucle.

Kevin H.
la source
-1

Voici une solution possible:

var x = 1.234000 // to become 1.234;
var y = 1.234001; // stays 1.234001

eval(x) --> 1.234
eval(y) --> 1.234001
Lune
la source
4
Vous n'avez pas besoin d'évaluation pour cette tâche simple! parseFloat()sera tout à fait approprié.
hutchbat
6
eval == mal. Ne l'utilisez jamais
eagor