Rimuovere insignificanti zeri finali da un numero?


157

Ho perso una chiamata API standard che rimuove gli zeri insignificanti finali da un numero?

Ex.

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

Number.toFixed () e Number.toPrecision () non sono proprio quello che sto cercando.


6
Ehm 1.234000 === 1.234.
Gumbo,

5
Sì, se si avvisa (x) si apre senza gli zeri finali
JKirchartz

50
Dopo aver lavorato con un numero di clienti, posso testimoniare che anche se 1.234000 === 1.234, i clienti non vogliono vedere quegli zeri extra se non ne hanno bisogno.
contactmatt

16
Usare parseFloat(n)?
Mr. Alien,

Questa è stata la soluzione più semplice che ha coperto tutti i casi limite per me, grazie @ Mr. Alien.
James Perih,

Risposte:


140

Se lo converti in una stringa non visualizzerà alcun zero finale, che non sono memorizzati nella variabile in primo luogo da quando è stato creato come un numero, non una stringa.

var n = 1.245000
var noZeroes = n.toString() // "1.245" 

6
Stavo per pubblicare del codice per eliminare gli zeri, ma la soluzione di Daniel sembra funzionare. Funziona anche con stringhe come "1.2345000". ("1.2345000" * 1) .toString (); // diventa 1.2345
Steven

7
Naturalmente, se il tuo var è già una stringa, devi prima convertirlo in un numero e poi di nuovo indietro
derekcohen,

Questo ha funzionato alla grande. Stavo avendo lo stesso problema, ho convertito float in stringa e quindi parseFloat per ripristinarlo nel formato giusto, solo senza gli zero finali.
Matt West,

10
Questa non è una soluzione completa. Non funziona quando hai una variabile con qualche errore di rappresentazione in virgola mobile, come: var n = 1.245000000000001(supponendo che sia insignificante essere rappresentato all'utente)
agosto

7
Può produrre risultati imprevisti per numeri come: 123111111111111111111111111111122222222222222222222222222222222222222222222222222222.00.00. La rappresentazione della stringa sarà in formato esponenziale: 1.231111111111111e + 81
Stas Makutin

227

Ho avuto un'istanza simile in cui volevo usare .toFixed()dove necessario, ma non volevo imbottire quando non lo era. Così ho finito per usare parseFloat insieme a toFixed.

Risolto senza imbottitura

parseFloat(n.toFixed(4));

Un'altra opzione che fa quasi la stessa cosa
Questa risposta può aiutare la tua decisione

Number(n.toFixed(4));

toFixedarrotonderà / pad il numero a una lunghezza specifica, ma lo convertirà anche in una stringa. La conversione in un tipo numerico non solo renderà il numero più sicuro da usare in modo aritmetico, ma eliminerà automaticamente anche tutti gli 0 finali. Per esempio:

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

Perché anche se definisci un numero con zeri finali vengono eliminati.

var n = 1.23000;
 // n == 1.23;

Nota che questo funziona solo se il numero rilevante di decimali è uguale o maggiore dell'argomento toFixed. Se il numero è ad esempio 1.200000, il risultato di toFixed (3) sarà 1.200 e, pertanto, non verranno rimossi tutti gli zeri finali.
Leopoldo Sanczyk,

@LeopoldoSanczyk No, è vero solo se stai usando toFixed, perché restituisce una stringa. I tipi di numero perdono automaticamente zeri finali. Ecco perché ho usato i due in tandem.
Gary,

@Gary, ritiro il mio commento, ho visto al parseFloat(n).toFixed(4);posto della tua vera risposta. Mi dispiace.
Leopoldo Sanczyk,

2
Perché no +(n.toFixed(4))?
Константин Ван,

3
upvoted! solo un problema con la tua risposta 0.00000005 viene convertito in 5e-8 come posso rimuovere zero insignificanti senza questo problema, sto lavorando con piccoli numeri come 0.000058000 dove gli zero alla fine devono essere rimossi
PirateApp

29

Per prima cosa ho usato una combinazione di matti-lyra e le risposte di gary:

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

risultati:

  • 1234870.98762341: "1234870.9876"
  • 1230009100: "1230009100"
  • 0,0012234: "0,0012"
  • 0.1200234: "0.12"
  • 0,000001231: "0"
  • 0.10001: "0.1000"
  • "asdf": "NaN" (quindi nessun errore di runtime)

Il caso alquanto problematico è 0,10001. Ho finito per usare questa versione più lunga:

    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" (quindi nessun errore di runtime)

Aggiornamento : e questa è la versione più recente di Gary (vedi commenti):

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

Questo dà gli stessi risultati di cui sopra.


1
Ho una soluzione regex pura che credo funzionitoFixed(4).replace(/([0-9]+(\.[1-9]+)?)(\.?0+$)/,"$1")
Gary,

1
Gah! Apparentemente non sono altrettanto bravo a infrangere il mio RegExes di altri. Non lascerò che questo mi batti! Ho eseguito questo contro tutti i tuoi casi di test più qualsiasi (valido) a cui potrei pensare([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)
Gary

1
Il regex è avido e talvolta rimuove uno "0" dalla parte intera! :-( Perché non solo replace(/[,.][1-9]+(0+)/,'')?
Sebastian Sebald,

1
Risposta sottovalutata.
Charlie,

1
@ w00t Oh, scusa, ora capisco. Ero il modo in cui ho provato quando ho fatto il mio (vedi link sopra). Il tuo non fallisce quando usi Fisso, perché il numero è garantito per avere un punto, ma non è riuscito nei miei test perché volevo che la regex funzionasse per qualsiasi numero, compresi numeri interi senza punto. Senza correggere, mangia uno zero alla fine. Colpa mia.
Geekley,

22

Il toFixedmetodo eseguirà l'arrotondamento appropriato, se necessario. Aggiungerà anche zero finali, che non è sempre l'ideale.

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

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

Se si esegue il cast del valore restituito su un numero, gli zero finali verranno eliminati. Questo è un approccio più semplice rispetto alla matematica di arrotondamento o troncamento.

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

+(4).toFixed(2);
//-> 4

1
difficile, ma esattamente quello che stavo cercando: rimuovere zeri finali significativi (che ovviamente abbiamo reso significativo attraverso la toFixedchiamata). è uno strano caso UX edge.
worc,

12

Avevo sostanzialmente lo stesso requisito e ho scoperto che non esiste un meccanismo incorporato per questa funzionalità.

Oltre a tagliare gli zeri finali, ho anche avuto la necessità di arrotondare e formattare l'output per la locale corrente dell'utente (ovvero 123.456.789).

Tutto il mio lavoro su questo è stato incluso come prettyFloat.js (con licenza MIT) su GitHub: https://github.com/dperish/prettyFloat.js


Esempi di utilizzo:

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)


Aggiornato - agosto 2018


Tutti i browser moderni ora supportano l' API di internazionalizzazione ECMAScript , che fornisce il confronto di stringhe sensibili al linguaggio, la formattazione dei numeri e la formattazione di data e ora.

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"

Per i browser meno recenti, è possibile utilizzare questo polyfill: https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en


Questo è quello che stavi cercando. È necessario creare un pacchetto npm.
EnZo,

Quindi dovrei probabilmente aggiornarlo, poiché ora è possibile tramite l'API di internazionalizzazione.
dperish,

2
Questo è molto utile, grazie per la condivisione e grazie anche per l'aggiornamento.
jaggedsoft,

11

Che ne dici di moltiplicare per uno come questo?

var x = 1.234000*1; // becomes 1.234

var y = 1.234001*1; // stays as 1.234001

9

Puoi provare questo per minimizzare i numeri fluttuanti

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

//output n = 0; 
// n = 3.14000; --> n = 3.14;

7

Risposta regex pura

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

Mi chiedo perché nessuno ne abbia dato uno!


Non funzionerà con i numeri (i numeri sono indicati nella domanda originale). Adoro la soluzione per una rappresentazione di stringhe!
BennyHilarious

6

Avevo bisogno di risolvere anche questo problema quando Django mostrava valori di tipo Decimale in un campo di testo. Ad esempio, quando "1" era il valore. Mostrerebbe "1.00000000". Se '1.23' fosse il valore, mostrerebbe '1.23000000' (Nel caso di un'impostazione 'decimal_places' di 8)

L'uso di parseFloat non è stato un'opzione per me poiché è possibile che non restituisca lo stesso valore esatto. toFixed non era un'opzione poiché non volevo arrotondare nulla, quindi ho creato una funzione:

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

Funziona, tuttavia è abbastanza inefficiente, poiché comporta la creazione di più stringhe per esecuzione. Immagina di eseguirlo su tutte le celle di una tabella, dove un buon numero era 0,0000. Un'opzione migliore sarebbe quella di determinare quanti zeri finali c'erano, quindi eseguire la sezione in una volta sola. Determinare cos'è un personaggio, è in gran parte efficiente, dividere le stringhe è meno.
Derek Nigel Bartram,

Ho fatto qualcosa di simile al tuo suggerimento Derek: github.com/rek/remove-trailing-zeros/blob/master/…
rekarnar

Il test di perf è qui: jsperf.com/remove-trailing-zeros/1 , avevi ragione, trovare gli zeri e rimuoverli è molto più veloce!
rekarnar,

4

Nessuna di queste soluzioni ha funzionato per me per numeri molto piccoli. http://numeraljs.com/ risolto questo per me.

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

numeral(0.00000001).format('0[.][00000000]');
// "0.00000001"

Non può gestire più di 6 precisione. Direi che questa libreria è inutile se è pensata per piccoli numeri. Sicuramente sconsigliato.
Daniel Kmak,

2

Se non è possibile utilizzare Float per qualsiasi motivo (come i soldi float coinvolti) e si sta già iniziando da una stringa che rappresenta un numero corretto, è possibile trovare questa soluzione utile. Converte una stringa che rappresenta un numero in una stringa che rappresenta un numero senza zero finali.

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

0

Dopo aver letto tutte le risposte - e i commenti - ho finito con questo:

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

So che l'uso evalpuò essere dannoso in qualche modo, ma questo mi ha aiutato molto.

Così:

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

Se si desidera limitare le cifre decimali, utilizzare toFixed()come altri hanno sottolineato.

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

Questo è tutto.


0

Avevo bisogno di rimuovere eventuali zeri finali ma mantenere almeno 2 decimali, inclusi eventuali zeri.
I numeri con cui sto lavorando sono 6 stringhe di numeri decimali, generate da .toFixed (6).

Risultato atteso:

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

Soluzione:

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

Logica:

Esegue la funzione loop se l'ultimo carattere stringa è zero.
Rimuovi l'ultimo carattere e aggiorna la variabile stringa.
Se l'ultimo carattere della stringa aggiornata non è uno zero, termina il ciclo.
Se la stringa aggiornata dal terzo all'ultimo carattere è un punto mobile, termina il ciclo.


-1

Ecco una possibile soluzione:

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

eval(x) --> 1.234
eval(y) --> 1.234001

4
Non hai bisogno di eval per questo semplice compito! parseFloat()sarà molto appropriato.
hutchbat,

6
eval == male. Non usarlo mai
eagor il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.