Вопрос по javascript – Преобразование длинного числа в сокращенную строку в JavaScript с особым требованием краткости

50

В JavaScript, как написать функцию, которая преобразует данный [edit:positive integer] число (менее 100 миллиардов) в трехбуквенное сокращение - где 0-9 и az / AZ считаются буквой, но точка (как она является крошечной во многих пропорциональных шрифтах) не будет и будет игнорируется лимит букв?

Этот вопрос связан сэта полезная тема, но это не то же самое; например, где эта функция будет поворачиваться, например, & quot; 123456 & gt; 1.23k & Quot; («123,5k», то есть 5 букв) Я ищу что-то, что делает «123456 - & gt; 0,1м & Quot; ("0 [.] 1 м", будучи 3 буквами). Например, это будет вывод ожидаемой функции (левый оригинал, правое идеальное возвращаемое значение):

0                      "0"
12                    "12"
123                  "123"
1234                "1.2k"
12345                "12k"
123456              "0.1m"
1234567             "1.2m"
12345678             "12m"
123456789           "0.1b"
1234567899          "1.2b"
12345678999          "12b"

Спасибо!

Update: Thanks! An answer is in and works per the requirements when the following amendments are made:

function abbreviateNumber(value) {
    var newValue = value;
    if (value >= 1000) {
        var suffixes = ["", "k", "m", "b","t"];
        var suffixNum = Math.floor( (""+value).length/3 );
        var shortValue = '';
        for (var precision = 2; precision >= 1; precision--) {
            shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
            var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
            if (dotLessShortValue.length <= 2) { break; }
        }
        if (shortValue % 1 != 0)  shortNum = shortValue.toFixed(1);
        newValue = shortValue+suffixes[suffixNum];
    }
    return newValue;
}
Также существует смесь между. а также,, так1001.5 превращается в миллионы вместо тысяч. vsync
Я перенес мой ответ наstackoverflow.com/a/10600491/711085 ninjagecko
Баз, мой текущий запуск - просто слегка переформатированная функция из связанного потока с упомянутыми проблемами. До того, как я попытаюсь оживить эту функцию, я надеялся, что кто-то еще, возможно, уже где-то написал умную функцию или знает, как это легко сделать. Csl, это здорово, большое спасибо! Будет ли это преобразование также делать «0,1 м»? стиль упоминается? Philipp Lenssen
Хотя и не JS, я сделал то же самое в C ++, который вы можете просмотреть наgist.github.com/1870641 - процесс будет таким же. Возможно, вам лучше поискать готовые решения. csl
то, что & APOS; sshortNum ? Вы никогда не используете, и он даже не объявлен .. vsync

Ваш Ответ

11   ответов
0

Code

  { value: 1, symbol: '' },
  { value: 1e3, symbol: 'k' },
  { value: 1e6, symbol: 'M' },
  { value: 1e9, symbol: 'G' },
  { value: 1e12, symbol: 'T' },
  { value: 1e15, symbol: 'P' },
  { value: 1e18, symbol: 'E' },
]

const abbreviateNumber = (number) => {
  if (number === 0) return number

  const tier = SI_PREFIXES.filter((n) => number >= n.value).pop()
  const numberFixed = (number / tier.value).toFixed(1)

  return `${numberFixed}${tier.symbol}`
}

abbreviateNumber(2000) // "2.0k"
abbreviateNumber(2500) // "2.5k"
abbreviateNumber(255555555) // "255.6M"

Test:

import abbreviateNumber from './abbreviate-number'

test('abbreviateNumber', () => {
  expect(abbreviateNumber(0)).toBe('0')
  expect(abbreviateNumber(100)).toBe('100')
  expect(abbreviateNumber(999)).toBe('999')

  expect(abbreviateNumber(1000)).toBe('1.0k')
  expect(abbreviateNumber(100000)).toBe('100.0k')
  expect(abbreviateNumber(1000000)).toBe('1.0M')
  expect(abbreviateNumber(1e6)).toBe('1.0M')
  expect(abbreviateNumber(1e10)).toBe('10.0G')
  expect(abbreviateNumber(1e13)).toBe('10.0T')
  expect(abbreviateNumber(1e16)).toBe('10.0P')
  expect(abbreviateNumber(1e19)).toBe('10.0E')

  expect(abbreviateNumber(1500)).toBe('1.5k')
  expect(abbreviateNumber(1555)).toBe('1.6k')

  expect(abbreviateNumber(undefined)).toBe('0')
  expect(abbreviateNumber(null)).toBe(null)
  expect(abbreviateNumber('100')).toBe('100')
  expect(abbreviateNumber('1000')).toBe('1.0k')
})
6

It does not attempt to deal with negative numbers:

const COUNT_ABBRS = [ '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ];

function formatCount(count, withAbbr = false, decimals = 2) {
    const i     = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000));
    let result  = parseFloat((count / Math.pow(1000, i)).toFixed(decimals));
    if(withAbbr) {
        result += `${COUNT_ABBRS[i]}`; 
    }
    return result;
}

Examples:

   formatCount(1000, true);
=> '1k'
   formatCount(100, true);
=> '100'
   formatCount(10000, true);
=> '10k'
   formatCount(10241, true);
=> '10.24k'
   formatCount(10241, true, 0);
=> '10k'
   formatCount(10241, true, 1)
=> '10.2k'
   formatCount(1024111, true, 1)
=> '1M'
   formatCount(1024111, true, 2)
=> '1.02M'
Это не решает поставленный вопрос, но это только то, чтоI ищу Благодарю.
Мне нравятся символы SI лучше, чем k, m, b. 1b в Америке / Великобритании - 1e9, но 1e12 во многих других странах.
0

здесь с примерами запуска скрипки решение @chucktator возвращает NaN во многих случаях. Это сработало идеально для меня.

0
            function converse_number (labelValue) {

                    // Nine Zeroes for Billions
                    return Math.abs(Number(labelValue)) >= 1.0e+9

                    ? Math.abs(Number(labelValue)) / 1.0e+9 + "B"
                    // Six Zeroes for Millions 
                    : Math.abs(Number(labelValue)) >= 1.0e+6

                    ? Math.abs(Number(labelValue)) / 1.0e+6 + "M"
                    // Three Zeroes for Thousands
                    : Math.abs(Number(labelValue)) >= 1.0e+3

                    ? Math.abs(Number(labelValue)) / 1.0e+3 + "K"

                    : Math.abs(Number(labelValue));

                }

0

function Converter(number, fraction) {
    let ranges = [
      { divider: 1, suffix: '' },
      { divider: 1e3, suffix: 'K' },
      { divider: 1e6, suffix: 'M' },
      { divider: 1e9, suffix: 'G' },
      { divider: 1e12, suffix: 'T' },
      { divider: 1e15, suffix: 'P' },
      { divider: 1e18, suffix: 'E' },
    ]
    //find index based on number of zeros
    let index = (Math.abs(number).toString().length / 3).toFixed(0)
    return (number / ranges[index].divider).toFixed(fraction) + ranges[index].suffix
}

Каждые 3 цифры имеют различный суффикс, это то, что я пытаюсь найти в первую очередь.

Итак, удалите отрицательный символif exists, а затем найдите, сколько 3 цифры в этом номере.

после этого найдите соответствующий суффикс, основанный на предыдущем расчете, добавленном к разделенному числу.

Converter(1500, 1)

Вернусь:

1.5K
20

и эффективным.

abbreviate_number = function(num, fixed) {
  if (num === null) { return null; } // terminate early
  if (num === 0) { return '0'; } // terminate early
  fixed = (!fixed || fixed < 0) ? 0 : fixed; // number of decimal places to show
  var b = (num).toPrecision(2).split("e"), // get power
      k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions
      c = k < 1 ? num.toFixed(0 + fixed) : (num / Math.pow(10, k * 3) ).toFixed(1 + fixed), // divide by power
      d = c < 0 ? c : Math.abs(c), // enforce -0 is 0
      e = d + ['', 'K', 'M', 'B', 'T'][k]; // append power
  return e;
}

Результаты:

for(var a='', i=0; i < 14; i++){ 
    a += i; 
    console.log(a, abbreviate_number(parseInt(a),0)); 
    console.log(-a, abbreviate_number(parseInt(-a),0)); 
}

0 0
-0 0
01 1
-1 -1
012 12
-12 -12
0123 123
-123 -123
01234 1.2K
-1234 -1.2K
012345 12.3K
-12345 -12.3K
0123456 123.5K
-123456 -123.5K
01234567 1.2M
-1234567 -1.2M
012345678 12.3M
-12345678 -12.3M
0123456789 123.5M
-123456789 -123.5M
012345678910 12.3B
-12345678910 -12.3B
01234567891011 1.2T
-1234567891011 -1.2T
0123456789101112 123.5T
-123456789101112 -123.5T
012345678910111213 12345.7T
-12345678910111212 -12345.7T
Гораздо лучшее решение
Благодарю. Я просто включил это в свой проект, и он работает как шарм. Отличный раствор, очень твердый.
Мне нравится этот подход, потому что он обрабатывает нецелые числа намного лучше, чем другие ответы.
10

numeraljs /

Если вы хотите конвертировать 1000 в 1k

console.log(numeral(1000).format('0a'));

и если вы хотите конвертировать 123400 в 123.4k попробуйте это

console.log(numeral(123400).format('0.0a'));
Фантастическое решение, если вы хотите установить стороннюю библиотеку
1

за внедренное интернационализированное поведение. Intl.NumberFormatter - это, в частности, средство форматирования локальных чисел. Так что этот код на самом деле учитывает ваши локально настроенные тысячи и десятичные разделители.

intlFormat(num) {
    return new Intl.NumberFormat().format(Math.round(num*10)/10);
}

abbreviateNumber(value) {
    let num = Math.floor(value);
    if(num >= 1000000000)
        return this.intlFormat(num/1000000000)+'B';
    if(num >= 1000000)
        return this.intlFormat(num/1000000)+'M';
    if(num >= 1000)
        return this.intlFormat(num/1000)+'k';
    return this.intlFormat(num);
}

abbreviateNumber (999999999999) // Дает 999B

Связанный вопрос:Сокращайте локализованное число в JavaScript для тысяч (1k) и миллионов (1m)

Но тогда суффиксы не локализуются.
45

что решение Ninjagecko не совсем соответствует стандарту, который вы хотели. Следующая функция делает:

function intToString (value) {
    var suffixes = ["", "k", "m", "b","t"];
    var suffixNum = Math.floor((""+value).length/3);
    var shortValue = parseFloat((suffixNum != 0 ? (value / Math.pow(1000,suffixNum)) : value).toPrecision(2));
    if (shortValue % 1 != 0) {
        var shortNum = shortValue.toFixed(1);
    }
    return shortValue+suffixes[suffixNum];
}

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

Edit by Philipp follows: С учетом следующих изменений он полностью соответствует всем требованиям!

function abbreviateNumber(value) {
    var newValue = value;
    if (value >= 1000) {
        var suffixes = ["", "k", "m", "b","t"];
        var suffixNum = Math.floor( (""+value).length/3 );
        var shortValue = '';
        for (var precision = 2; precision >= 1; precision--) {
            shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
            var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
            if (dotLessShortValue.length <= 2) { break; }
        }
        if (shortValue % 1 != 0)  shortNum = shortValue.toFixed(1);
        newValue = shortValue+suffixes[suffixNum];
    }
    return newValue;
}
Просто из любопытства: какой случай / требование я пропустил?
Они были незначительными и быстро исправлялись, основываясь на вашем великолепном ответе. Следующие тестовые числа были слегка пропущены: 123 стало 0,12 тыс. (Идеальный результат: 123, поскольку это еще 3 буквы и, следовательно, все в порядке); 123456 стало 0,12 м (идеально: 0,1 м, а 0,12 м - это 4 буквы, минус точка); то же самое для 0.12b, который с поправками теперь становится 0.1b. В очередной раз благодарим за помощь! Philipp Lenssen
Спасибо! Я внес некоторые поправки, чтобы они соответствовали требованиям на 100%, и отредактировал ваш ответ (надеюсь, что это правильный способ сделать это в StackOverflow, пожалуйста, измените его при необходимости). Superb! Philipp Lenssen
Я только что внес небольшую корректировку (еще предстоит рецензировать). Я добавил значение = Math.round (значение); в самом начале функции. Делая это, он не ломается, когда «значение» имеет десятичные знаки, например. 10025.26584 превратится в 10к вместо NaN
shortNum не определено в редакторе @ PhilippLenssen в концеif (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
6

https://stackoverflow.com/a/10600491/711085 , ваш ответ на самом деле немного короче, используя.substring(0,3):

function format(n) {
    with (Math) {
        var base = floor(log(abs(n))/log(1000));
        var suffix = 'kmb'[base-1];
        return suffix ? String(n/pow(1000,base)).substring(0,3)+suffix : ''+n;
    }
}

(Как обычно, не пользуйтесь математикой, если вы точно не знаете, что делаете;var pow=... и тому подобное приведет к безумным ошибкам. Смотрите ссылку для более безопасного способа сделать это.)

> tests = [-1001, -1, 0, 1, 2.5, 999, 1234, 
           1234.5, 1000001, Math.pow(10,9), Math.pow(10,12)]
> tests.forEach(function(x){ console.log(x,format(x)) })

-1001 "-1.k"
-1 "-1"
0 "0"
1 "1"
2.5 "2.5"
999 "999"
1234 "1.2k"
1234.5 "1.2k"
1000001 "1.0m"
1000000000 "1b"
1000000000000 "1000000000000"

Вам нужно будет отследить случай, когда результат & gt; = 1 триллион, если ваше требование для 3 символов строгое, иначе вы рискуете создать поврежденные данные, что было бы очень плохо.

Хорошее решение. Также сумасшедший реквизит для использования устаревшихwith заявление :)
работал отлично! Спасибо!
1

кажется, соответствует требуемым критериям. Получает вдохновение от ответа @ chuckator.

function abbreviateNumber(value) {

    if (value <= 1000) {
        return value.toString();
    }

    const numDigits = (""+value).length;
    const suffixIndex = Math.floor(numDigits / 3);

    const normalisedValue = value / Math.pow(1000, suffixIndex);

    let precision = 2;
    if (normalisedValue < 1) {
        precision = 1;
    }

    const suffixes = ["", "k", "m", "b","t"];
    return normalisedValue.toPrecision(precision) + suffixes[suffixIndex];
}
Я думаю, что этот ответ отличный. У меня был немного другой случай, когда я не хотел показывать значения с ведущими нулями. Я добавил, если (fixedValue.charAt (0) === '0') {return Controlvalue * 1000 + суффиксы [suffixIndex - 1]; } else {возврат отрегулированного значения + суффиксов [suffixIndex]; }

Похожие вопросы