ลบศูนย์ต่อท้ายที่ไม่มีนัยสำคัญออกจากตัวเลขหรือไม่


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

5
ใช่ถ้าคุณตื่นตัว (x) มันจะปรากฏขึ้นโดยไม่มีศูนย์ต่อท้าย
JKirchartz

50
หลังจากทำงานกับลูกค้าจำนวนมากฉันสามารถยืนยันได้ว่าแม้ว่า 1.234000 === 1.234 ลูกค้าไม่ต้องการเห็นศูนย์พิเศษเหล่านั้นหากพวกเขาไม่ต้องการ
contactmatt

16
ใช้งานparseFloat(n)หรือ
นายเอเลี่ยนคนต่างด้าว

นี่เป็นทางออกที่ง่ายที่สุดที่ครอบคลุมทุกกรณีสำหรับฉันขอบคุณ @ Mr.Alien
James Perih

คำตอบ:


140

หากคุณแปลงเป็นสตริงมันจะไม่แสดงศูนย์ใด ๆ ต่อท้ายซึ่งไม่ได้เก็บไว้ในตัวแปรในสถานที่แรกตั้งแต่มันถูกสร้างเป็นตัวเลขไม่ใช่สตริง

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

6
ฉันกำลังจะโพสต์โค้ดเพื่อตัดค่าศูนย์ แต่วิธีแก้ปัญหาของ Daniel ดูเหมือนจะใช้งานได้ มันใช้ได้กับ Strings เช่น "1.2345000" ("1.2345000" * 1) .toString (); // กลายเป็น 1.2345
Steven

7
แน่นอนถ้า var ของคุณเป็นสตริงอยู่แล้วคุณต้องแปลงเป็นตัวเลขก่อนแล้วจึงกลับมาอีกครั้ง
derekcohen

มันใช้งานได้ดีมาก ฉันมีปัญหาเดียวกันแปลง float เป็น string แล้วแยกวิเคราะห์เพื่อนำกลับมาใช้ในรูปแบบที่ถูกต้องโดยไม่มีเลขศูนย์ต่อท้าย
แมตต์เวสต์

10
นี่ไม่ใช่วิธีแก้ปัญหาที่สมบูรณ์ มันไม่ทำงานเมื่อคุณมีตัวแปรที่มีข้อผิดพลาดบางตัวแทนลอยจุดที่ชอบ: var n = 1.245000000000001(สมมติว่ามันเป็นเรื่องที่ไม่มีนัยสำคัญที่จะเป็นตัวแทนให้กับผู้ใช้)
ทำนาย

7
อาจสร้างผลลัพธ์ที่ไม่คาดคิดสำหรับหมายเลขที่ต้องการ: 123111111111111111111111111111112122222222222222222222222222222222222222222222222222222.00.00 การแสดงสตริงจะอยู่ในรูปแบบเลขชี้กำลัง: 1.23111111111111111e + 81
Stas Makutin

227

ฉันมีอินสแตนซ์ที่คล้ายกันซึ่งฉันต้องการใช้ใน.toFixed()กรณีที่จำเป็น แต่ฉันไม่ต้องการให้ช่องว่างภายในเมื่อไม่ได้ใช้ ดังนั้นฉันจึงลงเอยด้วยการใช้ parseFloat ร่วมกับการแก้ไข

toFixed โดยไม่มีช่องว่างภายใน

parseFloat(n.toFixed(4));

ตัวเลือกอื่นที่ทำในสิ่งเดียวกันเกือบ
คำตอบนี้อาจช่วยคุณตัดสินใจ

Number(n.toFixed(4));

toFixedจะปัดเศษ / ปัดตัวเลขให้มีความยาวเฉพาะ แต่จะแปลงเป็นสตริง การแปลงกลับไปเป็นตัวเลขจะไม่เพียง แต่ทำให้ตัวเลขปลอดภัยยิ่งขึ้นในการใช้เลขคณิตเท่านั้น ตัวอย่างเช่น:

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 ผลลัพธ์ของ toFixed (3) จะเป็น 1.200 และจะไม่มีเลขศูนย์ต่อท้ายทั้งหมดจะถูกลบ
Leopoldo Sanczyk

@LeopoldoSanczyk ไม่นั่นเป็นเรื่องจริงถ้าคุณเพิ่งใช้ toFixed เพราะมันคืนค่าสตริง ประเภทตัวเลขจะสูญเสียเลขศูนย์ต่อท้ายโดยอัตโนมัติ นั่นเป็นเหตุผลที่ฉันใช้ทั้งสองควบคู่
Gary

@ แกรี่ฉันถอนความคิดเห็นของฉันฉันได้เห็นparseFloat(n).toFixed(4);แทนที่จะเป็นคำตอบที่แท้จริงของคุณ ฉันขอโทษ.
Leopoldo Sanczyk

2
ทำไม+(n.toFixed(4))ล่ะ
КонстантинВан

3
upvoted! เพียงปัญหาเดียวที่มีคำตอบของคุณ 0.00000005 ได้รับการแปลงเป็น 5e-8 ฉันจะลบเลขศูนย์ที่ไม่มีนัยสำคัญได้อย่างไรโดยไม่มีปัญหานี้ฉันกำลังทำงานกับตัวเลขขนาดเล็กเช่น 0.000058000 โดยที่ศูนย์ท้ายต้องถูกลบออก
PirateApp

29

ฉันแรกใช้การรวมกันของคำตอบของ matti-lyra และแกรี่:

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" (ดังนั้นไม่มีข้อผิดพลาดรันไทม์)

อัปเดต : และนี่เป็นเวอร์ชันใหม่ของ Gary (ดูความคิดเห็น):

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

สิ่งนี้ให้ผลลัพธ์เช่นเดียวกับข้างต้น


1
ฉันมีโซลูชัน regex ที่สมบูรณ์แบบที่ฉันเชื่อว่าใช้ได้toFixed(4).replace(/([0-9]+(\.[1-9]+)?)(\.?0+$)/,"$1")
Gary

1
Gah! เห็นได้ชัดว่าฉันไม่ดีพอที่จะทำลาย RegExes ของฉันเองมากกว่าคนอื่น ๆ ฉันจะไม่ปล่อยให้สิ่งนี้เอาชนะฉันได้! ฉันใช้อันนี้กับกรณีทดสอบทั้งหมดของคุณรวมทั้งอันใดอันหนึ่งที่ฉันสามารถนึกได้([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)
Gary

1
regex คือโลภและบางครั้งก็เอา "0" ออกจากส่วนจำนวนเต็ม! :-( ทำไมไม่เพียงreplace(/[,.][1-9]+(0+)/,'')?
เซบาสเตียน Sebald

1
underrated คำตอบนี้
Charlie

1
@ w00t โอ้ขอโทษฉันเข้าใจแล้ว ฉันเป็นวิธีที่ฉันทดสอบเมื่อฉันสร้างของฉัน (ดูลิงค์ด้านบน) ของคุณไม่ได้ล้มเหลวเมื่อคุณใช้การคงที่เพราะตัวเลขรับประกันว่าจะมีจุด แต่มันก็ล้มเหลวในการทดสอบของฉันเพราะฉันต้องการให้ regex ทำงานได้กับตัวเลขใด ๆ รวมถึงจำนวนเต็มที่ไม่มีจุด หากไม่มีการแก้ไขคงกินเลขศูนย์ในตอนท้าย ความผิดฉันเอง.
geekley

22

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 edge ที่แปลก
worc

12

ฉันมีข้อกำหนดเดียวกันโดยทั่วไปและพบว่าไม่มีกลไกในตัวสำหรับฟังก์ชันนี้

นอกเหนือจากการตัดค่าศูนย์ต่อท้ายแล้วฉันยังต้องปัดเศษและจัดรูปแบบผลลัพธ์สำหรับตำแหน่งที่ตั้งปัจจุบันของผู้ใช้ (เช่น 123,456.789)

งานของฉันทั้งหมดนี้รวมอยู่ใน prettyFloat.js (สิทธิ์การใช้งาน MIT) บน GitHub: 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)


อัปเดต - สิงหาคม 2561


เบราว์เซอร์ที่ทันสมัยทั้งหมดนี้รองรับECMAScript Internationalization 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

ดังนั้นฉันควรจะอัปเดตสิ่งนี้เพราะตอนนี้เป็นไปได้ผ่านทาง Internationalization API
dperish

2
สิ่งนี้มีประโยชน์มากขอบคุณสำหรับการแบ่งปันและขอบคุณสำหรับการอัปเดตเช่นกัน
jaggedsoft


9

คุณสามารถลองอันนี้เพื่อลดจำนวนลอย

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

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

7

คำตอบ regex บริสุทธิ์

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

ฉันสงสัยว่าทำไมไม่มีใครให้เลย!


มันจะไม่ทำงานกับตัวเลข (ตัวเลขที่ระบุไว้ในคำถามเดิม) ฉันชอบวิธีแก้ปัญหาสำหรับการแสดงสตริง!
BennyHilarious

6

ฉันจำเป็นต้องแก้ปัญหานี้เช่นกันเมื่อ Django แสดงค่าประเภททศนิยมในฟิลด์ข้อความ เช่นเมื่อ '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 ตัวเลือกที่ดีกว่าคือการกำหนดจำนวนศูนย์ต่อท้ายที่มีอยู่แล้วทำการแบ่งในครั้งเดียว การพิจารณาว่าอักขระคืออะไรมีประสิทธิภาพส่วนใหญ่การแยกสตริงจะน้อยกว่า
Derek Nigel Bartram

ฉันทำสิ่งที่คล้ายกับคำแนะนำของคุณ Derek: 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 ตัวรวมทั้งเลขศูนย์ใด ๆ
ตัวเลขที่ฉันใช้คือสตริงตัวเลขทศนิยม 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

ตรรกะ:

เรียกใช้ฟังก์ชันลูปถ้าอักขระตัวสุดท้ายของสตริงเป็นศูนย์
ลบอักขระตัวสุดท้ายออกและอัพเดตตัวแปรสตริง
ถ้าอักขระตัวสุดท้ายของสตริงที่อัพเดตไม่ใช่ศูนย์ให้หยุดการวนซ้ำ
หากสตริงที่อัพเดตเป็นอักขระที่สามถึงอักขระสุดท้ายเป็นทศนิยม


-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

6
eval == ความชั่วร้าย อย่าใช้เลย
eagor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.