繁体   English   中英

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

[英]Remove insignificant trailing zeros from a number?

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

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

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

我有一个类似的实例,我想在必要时使用.toFixed() ,但我不想要填充。 所以我最终将 parseFloat 与 toFixed 结合使用。

toFixed 无填充

parseFloat(n.toFixed(4));

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

Number(n.toFixed(4));

toFixed会将数字toFixed /填充到特定长度,但也会将其转换为字符串。 将其转换回数字类型不仅会使数字在算术上使用更安全,而且还会自动删除任何尾随 0。 例如:

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

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

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

如果将其转换为字符串,则不会显示任何尾随零,这些零一开始就没有存储在变量中,因为它是作为数字创建的,而不是字符串。

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

我首先结合使用了 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')

这给出了与上面相同的结果。

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

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

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

如果将返回值转换为数字,则将删除那些尾随零。 这是一种比自己进行四舍五入或截断数学运算更简单的方法。

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

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

像这样乘以一怎么样?

var x = 1.234000*1; // becomes 1.234

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

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

除了修剪尾随零之外,我还需要根据用户的当前语言环境(即 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 ,它提供语言敏感的字符串比较、数字格式以及日期和时间格式。

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

你可以试试这个来缩小浮点数

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

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

纯正则表达式答案

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

我想知道为什么没有人给一个!

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

这些解决方案都不适用于非常小的数字。 http://numeraljs.com/为我解决了这个问题。

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

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

如果你使用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:如果您使用toFixed(0) ,则不需要replace

如果您出于任何原因不能使用浮点数(例如涉及货币浮点数)并且已经从表示正确数字的字符串开始,您可以找到这个解决方案很方便。 它将表示数字的字符串转换为表示不带尾随零的数字的字符串。

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

如果我们有一个数字的一​​些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
 */

上面在replace()使用的正则表达式解释如下:

  • 首先请注意| 正则表达式中的运算符,代表“OR”,因此, replace()方法将从s删除两种可能的子字符串,由(\\.0*)$部分匹配或由((?<=(\\..*))0*)$部分。
  • 正则表达式的(\\.0*)$部分匹配一个点符号,后跟所有零,直到s的末尾才匹配。 例如,这可能是0.0 (匹配并删除.0 )、 1.0 (匹配并删除.0 )、 0.000 (匹配并删除.000 )或点后全是零的任何类似字符串,因此,所有如果正则表达式的这部分匹配,则尾随零和点本身将被删除。
  • ((?<=(\\..*))0*)$部分仅匹配尾随零(位于点符号之后,后跟连续尾随零开始之前的任意数量的任何符号)。 例如,这可能是0.100 (尾随00匹配并删除)、 0.010 (最后一个0匹配并删除,请注意,由于“Positive Lookbehind Assertion”, 0.01部分根本不匹配,即(?<=(\\..*)) ,在正则表达式的这一部分中位于0*前面), 1.100010 (最后一个0被匹配并删除)等。
  • 如果表达式的两个部分都不匹配,则不会删除任何内容。 例如,这可能是100100.11等。因此,如果输入没有任何尾随零,则它保持不变。

还有一些使用.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'

要使用上面在replace()使用的正则表达式,我们可以访问: https : //regex101.com/r/owj9fz/1

这就是我的做法:

parseFloat(number.toString());

对于 TypeScript 错误,这也是一个很好的解决方法。 在某些情况下将数字更改为字符串的错误。

所以你要

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

没有附加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_);

在阅读了所有答案 - 和评论 - 我最终得到了这个:

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;

就是这样。

我需要删除任何尾随零,但至少保留 2 位小数,包括任何零。
我正在处理的数字是 6 个十进制数字字符串,由 .toFixed(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

逻辑:

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

我的解决方案如下:

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

我写了这个正则表达式来删除无关紧要的:从包含数字的字符串的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);

不幸的是,Safari 仍然不支持2018 年规范,该规范在正则表达式中为我们提供了后视。 自 2017 年 7 月 28 日以来,已针对此问题提供了一个公开的错误报告

好消息是,lookbehinds 确实适用于 Firefox 和所有 Chromium 衍生产品。 希望 Safari 将收到更多关于此合规性的请求并尽快实施此标准。

如果您还想处理数字错误,可以使用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"

使用 parseFloat() 对我有用。 对于为什么这些复杂的解决方案,我在这里摸不着头脑。

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

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

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

只是使用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) ); 

我认为下面的 function 可能接近你想要的。 我为我的应用程序编写了它。 它将始终采用标准符号 output,没有尾随零。 一些你可能不想要的东西,但如果你愿意,可以编辑掉。 它总是返回至少一位小数(例如 5=>"5.0")。 它也被限制为 10 位小数。 将其用作指南。

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

尝试捕获是因为并非所有东西都支持 endWith 并且我很懒惰。

暂无
暂无

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

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