Видалити незначні нулі з числа?


157

Чи пропустив я стандартний виклик API, який видаляє з числа незрозумілі нулі?

Вих.

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

Number.toFixed () та Number.toPrecision () - не зовсім те, що я шукаю.


6
Um, 1.234000 === 1.234.
Гумбо

5
Так, якщо ви будете насторожені (x), вони
спливуть

50
Працюючи з низкою клієнтів, я можу засвідчити, що навіть незважаючи на 1.234000 === 1.234, клієнти не хочуть бачити ці додаткові нулі, якщо вони не потребують.
contactmatt

16
Використовувати parseFloat(n)?
Містер

Це було найпростішим рішенням, яке охоплювало всі випадки справи для мене, дякую @ Mr.Alien.
Джеймс Перих

Відповіді:


140

Якщо ви перетворите його в рядок, він не відображатиме ніяких задніх нулів, які не зберігаються в змінній, в першу чергу, оскільки вони були створені у вигляді числа, а не рядка.

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

6
Я збирався опублікувати якийсь код, щоб зняти нулі, але рішення Даніеля, здається, працює. Він працює навіть для рядків типу "1,22345000". ("1,22345000" * 1) .toString (); // стає 1.2345
Стівен

7
Звичайно, якщо ваш var вже є рядком, вам потрібно спершу перетворити його в число, а потім знову
derekcohen

Це спрацювало чудово. У мене виникла та сама проблема, перетворена float в рядок, а потім parseFloat, щоб повернути її у потрібному форматі, лише без зворотних нулів.
Метт Вест

10
Це не повне рішення. Це не працює , якщо у вас є змінні з деякою плаваючою помилкою уявлення точки, як: var n = 1.245000000000001(передбачається , що вона незначна , щоб представити користувач)
віщун

7
Може створити несподівані результати для таких номерів, як: 12311111111111111111111111111222222222222222222222222222222222222222222222222222.00. Представлення рядків буде у експоненціальному форматі: 1.231111111111111e + 81
Стас Макутін

227

У мене був подібний екземпляр, де я хотів використовувати .toFixed()там, де потрібно, але я не хотів, щоб тампон був, коли його не було. Тому я в кінцевому підсумку використовував parseFloat спільно з toFixed.

toFIX без прокладки

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, результат toFixed (3) буде 1.200, і, отже, не будуть видалені всі проміжні нулі.
Леопольдо Санчик

@LeopoldoSanczyk Ні, це справедливо лише в тому випадку, якщо ви просто використовуєте toFixed, тому що він повертає рядок. Типи чисел автоматично втрачають кінцеві нулі. Ось чому я використав це два в тандемі.
Гері

@Gary, я відкликаю свій коментар, я бачив parseFloat(n).toFixed(4);замість вашої реальної відповіді. Мені шкода.
Леопольдо Санчик

2
Чому ні +(n.toFixed(4))?
Константин Ван

3
прихильне! тільки одна проблема з вашою відповіддю 0,00000005 перетворюється на 5e-8, як я можу видалити незначні нулі без цієї проблеми, я працюю з невеликими числами, такими як 0,000058000, де нулі в кінці потрібно видалити
PirateApp

29

Я вперше застосував поєднання відповідей матті-ліри та Ґері:

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")
Гарі

1
Гах! Мабуть, я не так вже й добре зламаю власні RegExes, ніж інші. Я не дам, щоб це мене побили! Я запустив цю на всі ваші тестові випадки плюс будь-яку (дійсну), яку я міг би придумати([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)
Gary

1
Регекс - це жадібність іноді видаляти "0" з цілої частини! :-( Чому б не просто replace(/[,.][1-9]+(0+)/,'')?
Себастьян Себальд,

1
Занижена відповідь на це.
Чарлі

1
@ w00t О, вибачте, зараз я розумію. Я був таким, як я тестував, коли робив свою (див. Посилання вище). Ваш не виходить з ладу, коли ви використовуєте toFixed, тому що число гарантовано має крапку, але в моїх тестах це не вдалося, тому що я хотів, щоб регулярний вираз працював для будь-якого числа, включаючи цілі числа без крапки. Без toFixed, він з'їдає нуль в кінці. Моє ліжко.
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.
worc

12

У мене були в основному однакові вимоги, і я виявив, що для цього функціоналу немає вбудованого механізму.

На додаток до обрізки кінцевих нулів, у мене також була необхідність округлення та форматування виводу для поточного локального пункту користувача (тобто 123456.789).

Вся моя робота над цим була включена як доситьFloat.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)


Оновлено - серпень 2018 року


Усі сучасні браузери тепер підтримують API інтернаціоналізації ECMAScript , який забезпечує порівняння мовних рядків, форматування чисел та форматування дати та часу.

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"

Для старих веб-переглядачів ви можете використовувати цю поліграфію: https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en


Це те, що шукали. Ви повинні створити пакет npm.
EnZo

Тому я, мабуть, мушу це оновити, оскільки це зараз можливо через API інтернаціоналізації.
дперіш

2
Це дуже корисно, дякую за спільний доступ і також дякую за оновлення.
jaggedsoft

11

Як щодо просто множення на одне подібне?

var x = 1.234000*1; // becomes 1.234

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

9

Ви можете спробувати цей, щоб мінімізувати плаваючі числа

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

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

7

Чиста відповідь на регулярний вираз

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

Цікаво, чому ніхто не дав!


Він не працюватиме з числами (цифри вказані в оригінальному запитанні). Я люблю рішення для представлення рядків!
BennyHilarious

6

Мені також потрібно було вирішити цю проблему, коли Джанго відображав значення десяткових типів у текстовому полі. Наприклад, коли значення було "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

Тест на Perf тут: 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 точністю. Я б сказав, що ця бібліотека марна, якщо вона призначена для невеликої кількості. Однозначно не рекомендується.
Даніель Кмак

2

Якщо ви не можете використовувати 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
Вам не потрібен eval для цього простого завдання! parseFloat()буде набагато доречніше
хачбат

6
eval == зло. Не використовуйте його ніколи
егор
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.