Remover zeros à direita insignificantes de um número?

157

Perdi uma chamada de API padrão que remove zeros insignificantes à direita de um número?

Ex.

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

Number.toFixed () e Number.toPrecision () não são exatamente o que estou procurando.

Steven
fonte
6
Hum 1.234000 === 1.234.
Gumbo
5
Sim, se você alertar (x), ele aparece sem os zeros à direita
JKirchartz 31/08/10
50
Depois de trabalhar com vários clientes, posso testemunhar que, embora 1,223000 === 1,223, os clientes não desejam ver esses zeros extras se não precisarem.
contactmatt
16
Usar parseFloat(n)?
Sr. Estrangeiro
Esta foi a solução mais fácil para todos os casos extremos, obrigado @ Mr.Alien.
James Perih 01/10/19

Respostas:

140

Se você convertê-lo em uma string, ele não exibirá zeros à direita, que não são armazenados na variável em primeiro lugar desde que foi criado como um número, não como uma string.

var n = 1.245000
var noZeroes = n.toString() // "1.245" 
Cristian Sanchez
fonte
6
Eu estava prestes a publicar um código para eliminar os zeros, mas a solução de Daniel parece funcionar. Até funciona para Strings como "1.2345000". ("1.2345000" * 1) .toString (); // torna-se 1,2345
Steven
7
Claro que, se o seu var já é uma string que você tem que convertê-lo para um número em primeiro lugar e depois volta novamente
derekcohen
Isso funcionou muito bem. Eu estava tendo o mesmo problema, converti float em string e, em seguida, analiseFloat para recuperá-lo no formato certo, apenas sem os zeros à direita.
Matt West
10
Esta não é uma solução completa. Ele não funciona quando você tem variável com alguns erros representação de ponto flutuante, como: var n = 1.245000000000001(assumindo que é insignificante para ser representado com o usuário)
áugure
7
Pode produzir resultados inesperados para números como: 123111111111111111111111111111122222222222222222222222222222222222222222222222222222.00. A representação da string estará no formato exponencial: 1.231111111111111e + 81
Stas Makutin:
227

Eu tive um exemplo semelhante em que queria usar .toFixed()quando necessário, mas não queria o preenchimento quando não estava. Então, acabei usando o parseFloat em conjunto com o toFixed.

Fixado sem preenchimento

parseFloat(n.toFixed(4));

Outra opção que faz quase a mesma coisa
Esta resposta pode ajudar sua decisão

Number(n.toFixed(4));

toFixedarredondará / preencherá o número em um comprimento específico, mas também o converterá em uma sequência. Converter isso de volta para um tipo numérico não apenas tornará o número mais seguro para usar aritmeticamente, mas também eliminará automaticamente os 0s à direita. Por exemplo:

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

Porque mesmo se você definir um número com zeros à direita, eles serão descartados.

var n = 1.23000;
 // n == 1.23;
Gary
fonte
Observe que isso funciona apenas se o número relevante de decimais for igual ou superior ao argumento toFixed. Se o número for, por exemplo, 1.200000, o resultado de toFixed (3) será 1.200 e, portanto, nem todos os zeros à direita serão removidos.
Leopoldo Sanczyk
@LeopoldoSanczyk Não, isso só é verdade se você estiver usando o toFixed, porque ele retorna uma string. Os tipos de números perdem automaticamente zeros à direita. Por isso usei os dois juntos.
Gary
@ Gary, retiro meu comentário, vi em parseFloat(n).toFixed(4);vez da sua resposta real. Eu sinto Muito.
Leopoldo Sanczyk
2
Por que não +(n.toFixed(4))?
precisa saber é o seguinte
3
votado! apenas um problema com sua resposta 0.00000005 é convertido para 5e-8 como posso remover zeros insignificantes sem esse problema, estou trabalhando com pequenos números como 0.000058000 onde zeros no final precisam ser removidos
PirateApp
29

Eu usei uma combinação das respostas de matti-lyra e gary:

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

Resultados:

  • 1234870.98762341: "1234870.9876"
  • 1230009100: "1230009100"
  • 0.0012234: "0,0012"
  • 0.1200234: "0.12"
  • 0.000001231: "0"
  • 0.10001: "0.1000"
  • "asdf": "NaN" (portanto, nenhum erro de tempo de execução)

O caso um tanto problemático é 0.10001. Acabei usando esta versão mais longa:

    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" (portanto, nenhum erro de tempo de execução)

Atualização : E esta é a versão mais recente de Gary (ver comentários):

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

Isso fornece os mesmos resultados acima.

w00t
fonte
1
Eu tenho uma solução regex puro que eu acredito obrastoFixed(4).replace(/([0-9]+(\.[1-9]+)?)(\.?0+$)/,"$1")
Gary
1
Gah! Aparentemente, não sou tão bom em quebrar meus próprios RegExes do que outros. Eu não vou deixar isso me vencer! Corri este contra todos os seus casos de teste mais qualquer um (válido) que eu poderia pensar([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)
Gary
1
O regex é ganancioso e às vezes remove um "0" da parte inteira! :-( Por que não, apenas replace(/[,.][1-9]+(0+)/,'')? #
999 Sebastian Sebald #
1
Resposta subestimada.
8308 Charlie
1
@ w00t Oh, desculpe, eu entendo agora. Eu era o jeito que testei quando fiz o meu (veja o link acima). O seu não falha quando você usa o toFixed, porque é garantido que o número tem um ponto, mas estava falhando nos meus testes porque eu queria que o regex funcionasse para qualquer número, incluindo números inteiros sem ponto. Sem o toFixed, o valor é zero no final. Foi mal.
Geekley 06/07/19
22

O toFixedmétodo fará o arredondamento apropriado, se necessário. Ele também adicionará zeros à direita, o que nem sempre é o ideal.

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

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

Se você converter o valor de retorno para um número, os zeros à direita serão eliminados. Essa é uma abordagem mais simples do que fazer sua própria matemática de arredondamento ou truncamento.

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

+(4).toFixed(2);
//-> 4
CJ
fonte
1
complicado, mas exatamente o que eu estava procurando: remover zeros à direita significativos (que é claro que fizemos significativo através da toFixedchamada). é um caso de borda UX estranho.
WORC
12

Eu tinha basicamente o mesmo requisito e descobri que não há mecanismo interno para essa funcionalidade.

Além de aparar os zeros à direita, também tive a necessidade de arredondar e formatar a saída para a localidade atual do usuário (ou seja, 123.456.789).

Todo o meu trabalho sobre isso foi incluído como prettyFloat.js (MIT licenciado) no GitHub: https://github.com/dperish/prettyFloat.js


Exemplos de uso:

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)


Atualizado - agosto de 2018


Todos os navegadores modernos agora oferecem suporte à API de Internacionalização do ECMAScript , que fornece comparação de strings sensíveis ao idioma, formatação de números e formatação de data e hora.

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"

Para navegadores mais antigos, você pode usar este polyfill: https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en

impertinente
fonte
Era isso que procurávamos. Você deve criar um pacote npm.
EnZo 29/08/18
Portanto, eu provavelmente deveria atualizar isso, pois agora isso é possível por meio da API de internacionalização.
Dperish
2
Isso é muito útil, obrigado por compartilhar e também pela atualização.
Jaggedsoft
11

Que tal apenas multiplicar por um como este?

var x = 1.234000*1; // becomes 1.234

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

Você pode tentar este para reduzir números flutuantes

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

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

Resposta regex pura

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

Eu me pergunto por que ninguém deu um!

João Costa
fonte
Não funcionará com números (os números são indicados na pergunta original). Eu amo a solução para uma representação de string!
BennyHilarious
6

Eu também precisava resolver esse problema quando o Django estava exibindo valores de tipo decimal em um campo de texto. Por exemplo, quando '1' era o valor. Ele mostraria '1.00000000'. Se '1,23' fosse o valor, ele mostraria '1,23000000' (no caso de uma configuração de 'decimal_places' de 8)

Usar parseFloat não era uma opção para mim, pois é possível que ele não retorne exatamente o mesmo valor. O toFixed não era uma opção, pois eu não queria arredondar nada, então criei uma função:

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
fonte
Isso funciona, no entanto, é bastante ineficiente, pois resulta na criação de várias strings por execução. Imagine executar isso em todas as células de uma tabela, onde um bom número era 0,0000. Uma opção melhor seria determinar quantos zeros à direita existiam e fazer a fatia de uma só vez. Determinar o que é um personagem é bastante eficiente, dividir as cordas é menos.
Derek Nigel Bartram
Eu fiz algo semelhante para a sua sugestão Derek: github.com/rek/remove-trailing-zeros/blob/master/...
rekarnar
O teste Perf está aqui: jsperf.com/remove-trailing-zeros/1 , você estava certo, encontrar os zeros e removê-los é muito mais rápido!
rekarnar
4

Nenhuma dessas soluções funcionou para mim por números muito pequenos. http://numeraljs.com/ resolveu isso para mim.

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

numeral(0.00000001).format('0[.][00000000]');
// "0.00000001"
Devon
fonte
Ele não pode lidar com mais de 6 precisão. Eu diria que esta biblioteca é inútil se for destinada a pequenos números. Definitivamente não é recomendado.
precisa
2

Se você não puder usar flutuadores por qualquer motivo (como dinheiro envolvido) e já estiver iniciando a partir de uma sequência que representa um número correto, poderá encontrar esta solução útil. Ele converte uma string representando um número em uma string representando o número sem zeros à direita.

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;
}
BennyHilarious
fonte
0

Depois de ler todas as respostas - e comentários - acabei com isso:

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

Eu sei que o uso evalpode ser prejudicial de alguma forma, mas isso me ajudou muito.

Assim:

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

Se você deseja limitar as casas decimais, use toFixed()como as outras pessoas apontaram.

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

É isso aí.

ed1nh0
fonte
0

Eu precisava remover quaisquer zeros à direita, mas manter pelo menos 2 casas decimais, incluindo zeros.
Os números com os quais estou trabalhando são seis seqüências de números decimais, geradas por .toFixed (6).

Resultado esperado:

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

Solução:

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

Lógica:

Execute a função de loop se o último caractere da cadeia for zero.
Remova o último caractere e atualize a variável de sequência.
Se o último caractere da string atualizada não for zero, termine o loop.
Se a sequência atualizada do terceiro ao último caractere for um ponto flutuante, termine o loop.

Kevin H.
fonte
-1

Aqui está uma solução possível:

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

eval(x) --> 1.234
eval(y) --> 1.234001
Lua
fonte
4
Você não precisa de avaliação para esta tarefa simples! parseFloat()será muito apropriado.
hutchbat
6
eval == mal. Não use nunca
eagor