从数字中删除不重要的尾随零?


157

我是否错过了一个标准API调用,该调用会从数字中删除尾随的零?

例如

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

Number.toFixed()和Number.toPrecision()并不是我想要的。


6
嗯,1.234000 === 1.234
Gumbo 2010年

5
是啊,如果你做的警报(X)它弹出没有尾随零
JKirchartz

50
在与许多客户合作之后,我可以证明,即使1.234000 === 1.234,客户也不需要看到那些多余的零。
contactmatt

16
使用parseFloat(n)
Alien先生2016年

对于我来说,这是涵盖所有极端情况的最简单解决方案,谢谢@Alien先生。
James Perih '18

Answers:


140

如果将其转换为字符串,它将不会显示任何结尾的零,因为它是作为数字而不是字符串创建的,因此不会首先存储在变量中。

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

6
我正准备发布一些代码以消除零,但Daniel的解决方案似乎有效。它甚至适用于“ 1.2345000”之类的字符串。(“ 1.2345000” * 1).toString(); //变为1.2345
史蒂文

7
当然,如果您的var已经是一个字符串,则必须先将其转换为数字,然后再返回
derekcohen 2011年

这很棒。我遇到了同样的问题,将float转换为字符串,然后将parseFloat转换为正确的格式,只是没有尾随零。
马特·韦斯特

10
这不是完整的解决方案。当您的变量带有一些浮点表示错误时,它将不起作用,例如:(var n = 1.245000000000001假设它对用户表示无关紧要)
2013年

7
可能会产生以下数字的意外结果:1231111111111111111111111111111222222222222222222222222222222222222222222222222222.00。字符串表示形式将为指数格式:1.231111111111111e + 81
Stas Makutin

227

我有一个类似的实例,我想.toFixed()在必要的地方使用它,但是我不想在不需要时使用填充。因此,我最终将parseFloat与toFixed结合使用。

固定而不填充

parseFloat(n.toFixed(4));

该做几乎同样的事情的另一个选择
这个答案可能会帮助你的决定

Number(n.toFixed(4));

toFixed会将数字四舍五入/填充为特定长度,但也会将其转换为字符串。将其转换回数字类型,不仅可以使数字更安全地用于算术运算,还可以自动删除任何结尾的0。例如:

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

因为即使您定义了一个带有尾随零的数字,它们也会被丢弃。

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

请注意,这仅在相关的小数位数等于或大于toFixed参数时才有效。例如,如果数字为1.200000,则toFi​​xed(3)的结果将为1.200,因此不会删除所有尾随零。
Leopoldo Sanczyk

@LeopoldoSanczyk不,仅当您仅使用toFixed时,这是正确的,因为它返回一个字符串。数字类型会自动丢失尾随零。这就是为什么我同时使用两者。
加里

@Gary,我撤回评论,我看到的parseFloat(n).toFixed(4);不是您的实际答案。对不起。
Leopoldo Sanczyk

2
为什么不+(n.toFixed(4))呢?
45КонстантинВан

3
赞!您的答案只有一个问题0.00000005被转换为5e-8,如何在不出现此问题的情况下删除不重要的零,我正在使用较小的数字(例如0.000058000),其中需要删除最后的零
PirateApp

29

我首先结合使用了matti-lyra和gary的答案:

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

结果:

  • 1234870.98762341:“ 1234870.9876”
  • 1230009100:“ 1230009100”
  • 0.0012234:“ 0.0012”
  • 0.1200234:“ 0.12”
  • 0.000001231:“ 0”
  • 0.10001:“ 0.1000”
  • “ asdf”:“ NaN”(因此没有运行时错误)

有问题的情况是0.10001。我最终使用了这个更长的版本:

    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”(因此没有运行时错误)

更新:这是加里的较新版本(请参阅评论):

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

得出与上述相同的结果。


1
我有一个我认为可以使用的纯正则表达式解决方案toFixed(4).replace(/([0-9]+(\.[1-9]+)?)(\.?0+$)/,"$1")
Gary

1
加!显然,我在打破自己的RegExes方面不如其他人。我不会让这打败我!我针对您所有的测试用例以及我能想到的任何(有效)用例进行了测试([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)
Gary

1
正则表达式是贪婪的,有时会从整数部分中删除“ 0”!:-(为什么不只是replace(/[,.][1-9]+(0+)/,'')呢?
Sebastian Sebald 2014年

1
低估了这个。
查理

1
@ w00t哦,对不起,我现在明白了。我是我做我的时候的测试方式(请参阅上面的链接)。当您使用toFixed时,您的函数不会失败,因为该数字保证有一个点,但是在我的测试中却失败了,因为我希望正则表达式适用于任何数字,包括不带点的整数。如果不固定,则最后吃零。我的错。
geekley

21

toFixed如果需要,该方法将进行适当的舍入。它还将添加尾随零,这并不总是理想的。

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

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

如果将返回值强制转换为数字,则那些尾随零将被删除。这比进行自己的舍入或截断数学要简单得多。

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

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

1
棘手,但正是我一直在寻找的:删除有效的尾随零(当然,我们在toFixed通话中通过有效的零)。这是一个奇怪的UX边缘案例。
worc

12

我有基本相同的要求,并且发现此功能没有内置的机制。

除了修整尾随的零外,我还需要四舍五入并格式化用户当前语言环境的输出(即123,456.789)。

我在这方面的所有工作都已包含在GitHub上的prettyFloat.js(获得MIT许可)中:https//github.com/dperish/prettyFloat.js


用法示例:

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)


更新-2018年8月


现在,所有现代浏览器都支持ECMAScript国际化API,该API提供了对语言敏感的字符串比较,数字格式以及日期和时间格式。

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"

对于较旧的浏览器,可以使用以下polyfill:https ://cdn.polyfill.io/v2/polyfill.min.js ? features = Intl.~locale.en


这就是寻找的东西。您必须创建一个npm软件包。
EnZo

因此,我应该更新它,因为现在可以通过国际化API来实现。
dperish

2
这非常有帮助,感谢您的分享,也感谢您的更新。
jaggedsoft '18

11

这样乘以一个怎么样?

var x = 1.234000*1; // becomes 1.234

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


7

纯正则表达式答案

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

我不知道为什么没人给!


它不适用于数字(数字在原始问题中有所说明)。我喜欢字符串表示的解决方案!
BennyHilarious

6

当Django在文本字段中显示Decimal类型值时,我也需要解决此问题。例如,当值为“ 1”时。它将显示为“ 1.00000000”。如果值为“ 1.23”,则将显示“ 1.23000000”(在“ decimal_places”设置为8的情况下)

使用parseFloat对我来说不是一个选择,因为有可能它不会返回完全相同的值。toFixed不是一个选择,因为我不想四舍五入,所以我创建了一个函数:

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

这种方法有效,但是效率非常低,因为它会导致每次执行都创建多个字符串。想象一下,在表中所有单元格为.00000的所有单元格上运行此命令。更好的选择是确定有多少尾随零,然后一次性进行切片。确定字符是什么,很大程度上是有效的,分割字符串则不太容易。
德里克·奈杰尔·巴特拉姆

我做了与您的建议德里克类似的事情:github.com/rek/remove-trailing-zeros/blob/master/…–
rekarnar

性能测试在这里:jsperf.com/remove-trailing-zeros/1,您是对的,找到零并删除它们会更快!
rekarnar

4

这些解决方案中没有一个对我有用。 http://numeraljs.com/为我解决了这个问题。

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

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

它不能处理超过6个精度。我想说的是,这个库对于少量数字来说是无用的。绝对不推荐。
Daniel Kmak

2

如果您由于某种原因不能使用Floats(例如涉及的money-floats),并且已经从表示正确数字的字符串开始,则可以轻松找到此解决方案。它将代表数字的字符串转换为代表没有尾随零的数字的字符串。

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

阅读所有答案和评论后,我得出以下结论:

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

我知道用 eval某种方式可能有害,但这对我很有帮助。

所以:

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

如果要限制小数位,请使用toFixed()其他指出的位数。

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

而已。


0

我需要删除所有结尾的零,但至少保留2个小数,包括任何零。
我正在使用的数字是.toFixed(6)生成的6个十进制数字字符串。

预期结果:

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

解:

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

逻辑:

如果字符串的最后一个字符为零,则运行循环功能。
删除最后一个字符并更新字符串变量。
如果更新的字符串的最后一个字符不为零,则结束循环。
如果更新的字符串的最后一个字符的最后一个是浮点,则结束循环。


-1

这是一个可能的解决方案:

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

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

4
您不需要评估就可以完成这个简单的任务!parseFloat()会很合适。
hutchbat 2014年

6
评估==邪恶。永远不要使用它
渴望
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.