Удалить незначительные конечные нули из числа?


157

Я пропустил стандартный вызов API, который удаляет завершающие незначительные нули из числа?

Ex.

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

Number.toFixed () и Number.toPrecision () не совсем то, что я ищу.


6
Хм 1.234000 === 1.234.
Гамбо

5
Да, если вы сделаете предупреждение (x), оно всплывает без конечных нулей
JKirchartz

50
После работы с несколькими клиентами я могу засвидетельствовать, что, хотя 1.234000 === 1.234, клиенты не хотят видеть эти дополнительные нули, если им это не нужно.
contactmatt

16
Использовать parseFloat(n)?
Мистер Чужой

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

Ответы:


140

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

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

6
Я собирался опубликовать некоторый код, чтобы убрать нули, но решение Дэниела, кажется, работает. Это даже работает для строк, таких как "1.2345000". ("1.2345000" * 1) .toString (); // становится 1.2345
Стивен

7
Конечно, если ваша переменная уже является строкой, вы должны сначала преобразовать ее в число, а затем обратно
derekcohen

Это сработало отлично. У меня была та же проблема, я преобразовал float в строку, а затем parseFloat, чтобы вернуть его в нужном формате, только без конечных нулей.
Мэтт Уэст

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

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

227

У меня был похожий случай, когда я хотел использовать его .toFixed()там, где это необходимо, но я не хотел, чтобы там были отступы. Поэтому я в итоге использовал parseFloat в сочетании с toFixed.

Исправлено без дополнения

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, потому что он возвращает строку. Типы чисел автоматически теряют конечные нули. Вот почему я использовал два в тандеме.
Гари

@ Гэри, я отозвал свой комментарий, я увидел parseFloat(n).toFixed(4);вместо твоего фактического ответа. Мне жаль.
Леопольдо Санчик

2
Почему нет +(n.toFixed(4))?
Константин Ван

3
upvoted! только одна проблема с вашим ответом 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
Г! По-видимому, я не так хорош в разрушении своих собственных регулярных выражений, как другие. Я не позволю этому победить меня! Я проверил этот на всех ваших тестовых случаях плюс любой (действительный), который я мог придумать([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)
Гари

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.
Wor

12

У меня было в основном то же самое требование, и я обнаружил, что для этой функции нет встроенного механизма.

В дополнение к обрезке конечных нулей мне также необходимо было округлить и отформатировать выходные данные для текущей локали пользователя (т. Е. 123 456,789).

Вся моя работа над этим была включена как prettyFloat.js (MIT Licensed) на 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.
dperish

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

Мне нужно было решить и эту проблему, когда 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. Лучшим вариантом было бы определить, сколько концевых нулей было, а затем сделать срез за один раз. Определение того, что символ, является в значительной степени эффективным, расщепление строк меньше.
Дерек Найджел Бартрам

Я сделал что-то похожее на ваше предложение Дерек: 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 точности. Я бы сказал, что эта библиотека бесполезна, если она предназначена для небольших чисел. Определенно не рекомендуется.
Даниэль Кмак

2

Если вы не можете использовать Float по какой-либо причине (например, с использованием money-float) и уже начинаете со строки, представляющей правильное число, вы можете найти это решение удобным. Он преобразует строку, представляющую число, в строку, представляющую число без конечных нулей.

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 == зло Никогда не используйте его
eagor
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.