簡體   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