简体   繁体   English

从数字中删除无关紧要的尾随零?

[英]Remove insignificant trailing zeros from a number?

Have I missed a standard API call that removes trailing insignificant zeros from a number?我是否错过了一个标准的 API 调用,该调用从数字中删除了尾随无关紧要的零?

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

Number.toFixed() and Number.toPrecision() are not quite what I'm looking for. Number.toFixed()Number.toPrecision()并不是我想要的。

I had a similar instance where I wanted to use .toFixed() where necessary, but I didn't want the padding when it wasn't.我有一个类似的实例,我想在必要时使用.toFixed() ,但我不想要填充。 So I ended up using parseFloat in conjunction with toFixed.所以我最终将 parseFloat 与 toFixed 结合使用。

toFixed without padding toFixed 无填充

parseFloat(n.toFixed(4));

Another option that does almost the same thing另一个几乎做同样事情的选择
This answer may help your decision这个答案可能有助于你的决定

Number(n.toFixed(4));

toFixed will round/pad the number to a specific length, but also convert it to a string. toFixed会将数字toFixed /填充到特定长度,但也会将其转换为字符串。 Converting that back to a numeric type will not only make the number safer to use arithmetically, but also automatically drop any trailing 0's.将其转换回数字类型不仅会使数字在算术上使用更安全,而且还会自动删除任何尾随 0。 For example:例如:

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

Because even if you define a number with trailing zeros they're dropped.因为即使您定义了一个带有尾随零的数字,它们也会被删除。

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

If you convert it to a string it will not display any trailing zeros, which aren't stored in the variable in the first place since it was created as a Number, not a String.如果将其转换为字符串,则不会显示任何尾随零,这些零一开始就没有存储在变量中,因为它是作为数字创建的,而不是字符串。

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

I first used a combination of matti-lyra and gary's answers:我首先结合使用了 matti-lyra 和 gary 的答案:

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

Results:结果:

  • 1234870.98762341: "1234870.9876" 1234870.98762341:“1234870.9876”
  • 1230009100: "1230009100" 1230009100:“1230009100”
  • 0.0012234: "0.0012" 0.0012234:“0.0012”
  • 0.1200234: "0.12" 0.1200234:“0.12”
  • 0.000001231: "0" 0.000001231:“0”
  • 0.10001: "0.1000" 0.10001:“0.1000”
  • "asdf": "NaN" (so no runtime error) "asdf": "NaN"(所以没有运行时错误)

The somewhat problematic case is 0.10001.有点问题的情况是 0.10001。 I ended up using this longer version:我最终使用了这个更长的版本:

    r = (+n).toFixed(4);
    if (r.match(/\./)) {
      r = r.replace(/\.?0+$/, '');
    }
  • 1234870.98762341: "1234870.9876" 1234870.98762341:“1234870.9876”
  • 1230009100: "1230009100" 1230009100:“1230009100”
  • 0.0012234: "0.0012" 0.0012234:“0.0012”
  • 0.1200234: "0.12" 0.1200234:“0.12”
  • 0.000001231: "0" 0.000001231:“0”
  • 0.10001: "0.1" 0.10001:“0.1”
  • "asdf": "NaN" (so no runtime error) "asdf": "NaN"(所以没有运行时错误)

Update : And this is Gary's newer version (see comments):更新:这是加里的新版本(见评论):

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

This gives the same results as above.这给出了与上面相同的结果。

The toFixed method will do the appropriate rounding if necessary.如有必要, toFixed方法将进行适当的舍入。 It will also add trailing zeroes, which is not always ideal.它还会添加尾随零,这并不总是理想的。

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

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

If you cast the return value to a number, those trailing zeroes will be dropped.如果将返回值转换为数字,则将删除那些尾随零。 This is a simpler approach than doing your own rounding or truncation math.这是一种比自己进行四舍五入或截断数学运算更简单的方法。

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

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

How about just multiplying by one like this?像这样乘以一怎么样?

var x = 1.234000*1; // becomes 1.234

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

I had the basically the same requirement, and found that there is no built-in mechanism for this functionality.我有基本相同的要求,并发现此功能没有内置机制。

In addition to trimming the trailing zeros, I also had the need to round off and format the output for the user's current locale (ie 123,456.789).除了修剪尾随零之外,我还需要根据用户的当前语言环境(即 123,456.789)对输出进行四舍五入和格式化。

All of my work on this has been included as prettyFloat.js (MIT Licensed) on GitHub: https://github.com/dperish/prettyFloat.js我在这方面的所有工作都包含在 GitHub 上的 prettyFloat.js(MIT 许可): https : //github.com/dperish/prettyFloat.js


Usage Examples:用法示例:

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)


Updated - August, 2018更新 - 2018 年 8 月


All modern browsers now support the ECMAScript Internationalization API , which provides language sensitive string comparison, number formatting, and date and time formatting.所有现代浏览器现在都支持ECMAScript 国际化 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"

For older browsers, you can use this polyfill: https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en对于较旧的浏览器,您可以使用此 polyfill: https ://cdn.polyfill.io/v2/polyfill.min.js ? features = Intl.~locale.en

You can try this one to minify floating numbers你可以试试这个来缩小浮点数

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

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

Pure regex answer纯正则表达式答案

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

I wonder why no one gave one!我想知道为什么没有人给一个!

I needed to solve this problem too when Django was displaying Decimal type values in a text field.当 Django 在文本字段中显示 Decimal 类型值时,我也需要解决这个问题。 Eg when '1' was the value.例如,当 '1' 是值时。 It would show '1.00000000'.它会显示“1.00000000”。 If '1.23' was the value, it would show '1.23000000' (In the case of a 'decimal_places' setting of 8)如果 '1.23' 是值,它将显示 '1.23000000'(在 'decimal_places' 设置为 8 的情况下)

Using parseFloat was not an option for me since it is possible it does not return the exact same value.使用parseFloat对我来说不是一个选择,因为它可能不会返回完全相同的值。 toFixed was not an option since I did not want to round anything, so I created a function: 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;
}

None of these solutions worked for me for very small numbers.这些解决方案都不适用于非常小的数字。 http://numeraljs.com/ solved this for me. http://numeraljs.com/为我解决了这个问题。

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

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

If you use toFixed(n) where n > 0, a more simple and stable (no more float operations) solution can be:如果你使用toFixed(n)其中 n > 0,一个更简单和稳定(没有更多浮点运算)的解决方案可以是:

(+n).toFixed(2).replace(/(\.0+|0+)$/, '')


// 0 => 0
// 0.1234 => 0.12
// 0.1001 => 0.1

// 1 => 1
// 1.1234 => 1.12
// 1.1001 => 1.1

// 100 => 100
// 100.1234 => 100.12
// 100.1001 => 100.1

PS: if you use toFixed(0) , then no replace is needed. PS:如果您使用toFixed(0) ,则不需要replace

If you cannot use Floats for any reason (like money-floats involved) and are already starting from a string representing a correct number, you could find this solution handy.如果您出于任何原因不能使用浮点数(例如涉及货币浮点数)并且已经从表示正确数字的字符串开始,您可以找到这个解决方案很方便。 It converts a string representing a number to a string representing number w/out trailing zeroes.它将表示数字的字符串转换为表示不带尾随零的数字的字符串。

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

If we have some s string representation of a number, which we can get for example using the .toFixed(digits) method of Number (or by any other means), then for removal of insignificant trailing zeros from the s string we can use:如果我们有一个数字的一​​些s字符串表示,例如我们可以使用Number.toFixed(digits) 方法(或通过任何其他方式)获得,那么为了从s字符串中删除无关紧要的尾随零,我们可以使用:

s.replace(/(\.0*|(?<=(\..*))0*)$/, '')

/**********************************
 * Results for various values of s:
 **********************************
 *
 * "0" => 0
 * "0.000" => 0
 * 
 * "10" => 10
 * "100" => 100
 * 
 * "0.100" => 0.1
 * "0.010" => 0.01
 * 
 * "1.101" => 1.101
 * "1.100" => 1.1
 * "1.100010" => 1.10001
 * 
 * "100.11" => 100.11
 * "100.10" => 100.1
 */

Regular expression used above in the replace() is explained below:上面在replace()使用的正则表达式解释如下:

  • In the first place please pay the attention to the |首先请注意| operator inside the regular expression, which stands for "OR", so, the replace() method will remove from s two possible kinds of substring, matched either by the (\\.0*)$ part OR by the ((?<=(\\..*))0*)$ part.正则表达式中的运算符,代表“OR”,因此, replace()方法将从s删除两种可能的子字符串,由(\\.0*)$部分匹配或由((?<=(\\..*))0*)$部分。
  • The (\\.0*)$ part of regex matches a dot symbol followed by all the zeros and nothing else till to the end of the s .正则表达式的(\\.0*)$部分匹配一个点符号,后跟所有零,直到s的末尾才匹配。 This might be for example 0.0 ( .0 is matched & removed), 1.0 ( .0 is matched & removed), 0.000 ( .000 is matched & removed) or any similar string with all the zeros after the dot, so, all the trailing zeros and the dot itself will be removed if this part of regex will match.例如,这可能是0.0 (匹配并删除.0 )、 1.0 (匹配并删除.0 )、 0.000 (匹配并删除.000 )或点后全是零的任何类似字符串,因此,所有如果正则表达式的这部分匹配,则尾随零和点本身将被删除。
  • The ((?<=(\\..*))0*)$ part matches only the trailing zeros (which are located after a dot symbol followed by any number of any symbol before start of the consecutive trailing zeros). ((?<=(\\..*))0*)$部分仅匹配尾随零(位于点符号之后,后跟连续尾随零开始之前的任意数量的任何符号)。 This might be for example 0.100 (trailing 00 is matched & removed), 0.010 (last 0 is matched & removed, note that 0.01 part do NOT get matched at all thanks to the "Positive Lookbehind Assertion", ie (?<=(\\..*)) , which is in front of 0* in this part of regex), 1.100010 (last 0 is matched & removed), etc.例如,这可能是0.100 (尾随00匹配并删除)、 0.010 (最后一个0匹配并删除,请注意,由于“Positive Lookbehind Assertion”, 0.01部分根本不匹配,即(?<=(\\..*)) ,在正则表达式的这一部分中位于0*前面), 1.100010 (最后一个0被匹配并删除)等。
  • If neither of the two parts of expression will match, nothing gets removed.如果表达式的两个部分都不匹配,则不会删除任何内容。 This might be for example 100 or 100.11 , etc. So, if an input does not have any trailing zeros then it stays unchanged.例如,这可能是100100.11等。因此,如果输入没有任何尾随零,则它保持不变。

Some more examples using .toFixed(digits) (Literal value "1000.1010" is used in the examples below, but we can assume variables instead):还有一些使用.toFixed(digits)的例子(下面的例子中使用了文字值“1000.1010”,但我们可以假设变量):

let digits = 0; // Get `digits` from somewhere, for example: user input, some sort of config, etc.

(+"1000.1010").toFixed(digits).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000'

(+"1000.1010").toFixed(digits = 1).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.1'


(+"1000.1010").toFixed(digits = 2).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.1'


(+"1000.1010").toFixed(digits = 3).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'


(+"1000.1010").toFixed(digits = 4).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'


(+"1000.1010").toFixed(digits = 5).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'

(+"1000.1010").toFixed(digits = 10).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'

To play around with the above regular expression used in replace() we can visit: https://regex101.com/r/owj9fz/1要使用上面在replace()使用的正则表达式,我们可以访问: https : //regex101.com/r/owj9fz/1

This is how I do it:这就是我的做法:

parseFloat(number.toString());

This is a good workaround for the TypeScript bug too.对于 TypeScript 错误,这也是一个很好的解决方法。 The bug that changes number to string in certain situations.在某些情况下将数字更改为字符串的错误。

So you want所以你要

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

No string s attached, just try Number() .没有附加string ,只需尝试Number()

 var x = 1.234000, // to become 1.234 y = 1.234001, // stays 1.234001 x_ = Number(x), y_ = Number(y); console.log(x_,y_);

After reading all of the answers - and comments - I ended up with this:在阅读了所有答案 - 和评论 - 我最终得到了这个:

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

I know using eval can be harmful somehow but this helped me a lot.我知道使用eval可能会以某种方式有害,但这对我有很大帮助。

So:所以:

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

If you want to limit the decimal places, use toFixed() as others pointed out.如果你想限制小数位,就像其他人指出的那样使用toFixed()

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

That's it.就是这样。

I needed to remove any trailing zeros but keep at least 2 decimals, including any zeros.我需要删除任何尾随零,但至少保留 2 位小数,包括任何零。
The numbers I'm working with are 6 decimal number strings, generated by .toFixed(6).我正在处理的数字是 6 个十进制数字字符串,由 .toFixed(6) 生成。

Expected Result:预期结果:

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

Logic:逻辑:

Run loop function if string last character is a zero.如果字符串最后一个字符为零,则运行循环函数。
Remove the last character and update the string variable.删除最后一个字符并更新字符串变量。
If updated string last character is not a zero, end loop.如果更新后的字符串最后一个字符不是零,则结束循环。
If updated string third to last character is a floating point, end loop.如果更新后的字符串倒数第三个字符是浮点数,则结束循环。

My solution is as follow:我的解决方案如下:

export const floatToStr = (f, ndigit = 2) => {
    const str = f.toFixed(ndigit)
    return ndigit
        ? str
            .replace(/0*$/g, '')
            .replace(/\.$/, '')
        : str
}

I wrote this regular expression to remove insignificant: zeros, decimals, and spaces from the beginning and end of strings containing numbers:我写了这个正则表达式来删除无关紧要的:从包含数字的字符串的beginning and end删除zeros, decimals, and spaces

 const rxInsignificant = /^[\\s0]+|(?<=\\..*)[\\s0.]+$|\\.0+$|\\.$/gm; let ary = [ "001.230", "2.", "3.00", " 0000000000000010000.10000000000000000000000 "]; ary = ary.map((str)=> { str = str.replace(rxInsignificant,''); return str; }); console.log(ary);

Unfortunately, Safari still doesn't support the 2018 specification that gave us lookbehinds in regular expressions.不幸的是,Safari 仍然不支持2018 年规范,该规范在正则表达式中为我们提供了后视。 There has been an open bug report for this issue since 07-28-2017.自 2017 年 7 月 28 日以来,已针对此问题提供了一个公开的错误报告

The good news is that lookbehinds do work in Firefox and in all Chromium derivatives.好消息是,lookbehinds 确实适用于 Firefox 和所有 Chromium 衍生产品。 Hopefully, Safari will receive more requests for this compliance and implement this standard soon.希望 Safari 将收到更多关于此合规性的请求并尽快实施此标准。

If you'd also like to deal with numeric errors, you could use Intl.NumberFormat or Number.toLocaleString()如果您还想处理数字错误,可以使用Intl.NumberFormatNumber.toLocaleString()

new Intl.NumberFormat().format(0.0100) // "0.01"
new Intl.NumberFormat().format(0.010000000000001) // "0.01"
new Intl.NumberFormat().format(0.009999999999999) // "0.01"
console.log((0.0100).toLocaleString()) // "0.01"
console.log((0.010000000000001).toLocaleString()) // "0.01"
console.log((0.009999999999999).toLocaleString()) // "0.01"

Using parseFloat() did the trick for me.使用 parseFloat() 对我有用。 I'm scratching my head here as to why those complicated solutions.对于为什么这些复杂的解决方案,我在这里摸不着头脑。

Here's a possible solution:这是一个可能的解决方案:

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

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

Just a simple math alternative to using toFixed 只是使用toFixed的简单数学替代方法

 function truncateNumber( num, precision ){ let c = Math.pow(10,precision); return Math.trunc( num*c )/c; } console.log( truncateNumber(1234.5678, 4) ); console.log( truncateNumber(1234.56, 4) ); 

I think the following function may be close to what you want.我认为下面的 function 可能接近你想要的。 I wrote it for an application of mine.我为我的应用程序编写了它。 It will always output in standard notation with no trailing zeros.它将始终采用标准符号 output,没有尾随零。 A few things you may not want but can edit out if you like.一些你可能不想要的东西,但如果你愿意,可以编辑掉。 It will always return at least one decimal(ex 5=>"5.0").它总是返回至少一位小数(例如 5=>"5.0")。 It also is limited to 10 decimals.它也被限制为 10 位小数。 Use it as a guide.将其用作指南。

const toDecimalStr(value)=>{
  let str=value.toFixed(10).replace(/([0]+)$/,"");
  try {
    if (str.endsWith(".")) str+='0';
  } catch (e) {
    str+='0';
  }
  return str;
}

the try catch is because not everything supports endsWith and I was being lazy.尝试捕获是因为并非所有东西都支持 endWith 并且我很懒惰。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM