将长整数转换为JavaScript中的缩写字符串,并有特殊的简短要求


79

在JavaScript中,如何编写将给定的[edit:正整数]数字(低于1000亿)转换为3个字母的缩写的函数-其中0-9和az / AZ被视为字母,但是点(因为在许多比例字体中是如此之小)不会,并且会因为字母限制而被忽略?

这个问题与此有用的线程有关,但是并不相同。例如,该函数将变为“ 123456-> 1.23k”(“ 123.5k”为5个字母),我正在寻找执行“ 123456-> 0.1m”(“ 0 [。] 1m”为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"

谢谢!

更新:谢谢!进行以下修改时,答案是正确的并符合要求:

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)  shortValue = shortValue.toFixed(1);
        newValue = shortValue+suffixes[suffixNum];
    }
    return newValue;
}

虽然不是JS,但我已经在C ++中完成了相同的工作,您可以在gist.github.com/1870641上进行查看-过程将相同。不过,寻找现成的解决方案可能会更好。
csl 2012年

Baz,我当前的开始只是链接线程中的一个轻度重新格式化的函数,上面提到了一些问题。在尝试完善该功能之前,我希望别人可能已经在某处编写了一个智能功能,或者知道如何轻松地实现该功能。Csl,太好了,非常感谢!转换还会提到“ 0.1m”样式吗?
菲利普·伦森


9
什么shortNum啊 -您从未使用过的,甚至都没有声明过。
vsync

1
.和之间也有混合,,因此1001.5变成了几百万而不是数千。
vsync 2015年

Answers:


60

我相信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) {
        shortValue = shortValue.toFixed(1);
    }
    return shortValue+suffixes[suffixNum];
}

对于大于99万亿的值,将不添加字母,可以通过将其附加到“后缀”数组来轻松地对其进行修复。

Philipp的编辑如下:通过以下更改,它完全符合所有要求!

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)  shortValue = shortValue.toFixed(1);
        newValue = shortValue+suffixes[suffixNum];
    }
    return newValue;
}

谢谢!我做了一些修改,以使其100%符合要求,并编辑了您的答案(我希望这是在StackOverflow中进行修改的正确方法,请根据需要进行更改)。高超!
菲利普·列森

出于好奇:我错过了哪种情况/要求?
chucktator 2012年

1
这些都是次要的,并会根据您的好答案迅速进行修改。稍微遗漏了以下测试编号:123变为0.12k(理想结果:123,因为它仍然是3个字母,因此还可以);123456变成0.12m(理想情况是0.1m,因为0.12m是4个字母,减去点);对于0.12b相同,现在经过修改后变为0.1b。再次感谢你的帮助!
菲利普·伦森

1
我对此做了一个小的调整(但还需要同行评审)。我添加了值= Math.round(value); 到功能的最开始 这样,当“值”具有小数位时,它不会中断。10025.26584将变成10k,而不是NaN
Daniel Tonon

2
shortNum在末尾的@PhilippLenssen编辑中if (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
未定义

43

这也处理非常大的值,并且更加简洁高效。

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

我喜欢这种方法,因为它比其他答案更好地处理了非整数问题。
Grant H.

更好的解决方案
Danillo Corvalan

谢谢。我只是将其放入我的项目中,它就像一个魅力。很棒的解决方案,非常扎实。
spieglio

对于非常小的值(例如5e-18),它将返回“ 0T”,因此我添加了以下内容:if (num < 1e-3) { return '~0'; }
Paul Razvan Berg,

16

使用Math对象,映射对象,for循环等,该线程上的许多答案变得相当复杂。但是这些方法实际上并没有真正改善设计-它们引入了更多的代码行,更多的复杂性和更多的内存开销。在评估了几种方法之后,我认为手动方法最容易理解,并且性能最高。

const formatCash = n => {
  if (n < 1e3) return n;
  if (n >= 1e3 && n < 1e6) return +(n / 1e3).toFixed(1) + "K";
  if (n >= 1e6 && n < 1e9) return +(n / 1e6).toFixed(1) + "M";
  if (n >= 1e9 && n < 1e12) return +(n / 1e9).toFixed(1) + "B";
  if (n >= 1e12) return +(n / 1e12).toFixed(1) + "T";
};

console.log(formatCash(1235000));


这绝对是公认的答案。到目前为止!感谢@tfmontague
Pedro Ferreira

14

我认为您不能尝试使用此数字js /

如果您想将1000转换为1k

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

如果要将123400转换为123.4k,请尝试

console.log(numeral(123400).format('0.0a'));

如果您愿意安装第三方库的话,那就是很棒的解决方案
Colby Cox

有没有一种方法可以使用,0.0a但是当数字为1000时1k不显示1.0k?(修剪零点)
Paul Razvan Berg,

14

我认为这是一个相当优雅的解决方案。它不会尝试处理负数

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;
}

例子

   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'

6
这不能解决所提出的问题,但这只是要寻找的。谢谢。
leff

我喜欢SI符号胜过k,m,b。美国/英国的1b是1e9,而其他许多国家/地区则是1e12。
克里斯蒂安·韦斯特贝克

8

现代,简便,内置,高度可定制和“无代码”的方式:Intl.FormatNumber格式函数(兼容性图

var numbers = [98721, 9812730,37462,29,093484620123, 9732,0283737718234712]
for(let num of numbers){
  console.log(new Intl.NumberFormat( 'en-US', { maximumFractionDigits: 1,notation: "compact" , compactDisplay: "short" }).format(num));
}
98.7K
9.8M
37.5K
29
93.5B
9.7K
283.7T

笔记:


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;
    }
}

(像往常一样,除非您确切地知道自己在做什么,否则不要使用Math;进行分配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"

如果您对3个字符的要求严格,则需要赶上结果> = 1万亿的情况,否则您就有可能创建损坏的数据,这将是非常糟糕的。


不错的解决方案。也是使用过时的with声明的疯狂道具:)
stwilz

3

const SI_PREFIXES = [
  { 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"

测试:

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')
})

在尝试了该线程中的上述所有解决方案之后,这是唯一可以正常工作的解决方案。谢谢达尼洛!
ty。

3

这是另一种看法。我希望123456是123.4K,而不是0.1M

function convert(value) {

    var length = (value + '').length,
        index = Math.ceil((length - 3) / 3),
        suffix = ['K', 'M', 'G', 'T'];

    if (length < 4) return value;
    
    return (value / Math.pow(1000, index))
           .toFixed(1)
           .replace(/\.0$/, '') + suffix[index - 1];

}

var tests = [1234, 7890, 123456, 567890, 800001, 2000000, 20000000, 201234567, 801234567, 1201234567];
for (var i in tests)
    document.writeln('<p>convert(' + tests[i] + ') = ' + convert(tests[i]) + '</p>');


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];
}

我认为这个答案很好。我有一个略有不同的情况,我不想显示前导零的值。我添加了if(adjustedValue.charAt(0)==='0'){return AdjustedValue * 1000 +后缀[suffixIndex-1]; } else {返回AdjustedValue +后缀[suffixIndex]; }
user3162553 '16

1

我正在使用此函数来获取这些值。

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位数字都有不同的后缀,这就是我要首先找到的。

因此,删除负号(如果存在),则将其,然后找出该数字中有多少个3位数字。

之后,根据先前的计算找到适当的后缀,并将其添加到除数中。

Converter(1500, 1)

将返回:

1.5K

这里有些不对劲。Converter(824492,1)将返回0.8M。它应该返回824k
塞巴斯蒂安·

0

Intl是用于实现国际化行为的Javascript标准“包”。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)的本地化数字


但是后缀并没有被本地化。
glen-84,18年

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));

                }

alert(converse_number(100000000000));


0

@尼姆萨拉姆

对于以下情况,您的解决方案将是不可取的:

Input 50000
Output 50.0k

以下解决方案将正常工作。

const convertNumberToShortString = (
  number: number,
  fraction: number
) => {
  let newValue: string = number.toString();
  if (number >= 1000) {
    const ranges = [
      { divider: 1, suffix: '' },
      { divider: 1e3, suffix: 'k' },
      { divider: 1e6, suffix: 'm' },
      { divider: 1e9, suffix: 'b' },
      { divider: 1e12, suffix: 't' },
      { divider: 1e15, suffix: 'p' },
      { divider: 1e18, suffix: 'e' }
    ];
    //find index based on number of zeros
    const index = Math.floor(Math.abs(number).toString().length / 3);
    let numString = (number / ranges[index].divider).toFixed(fraction);
    numString =
      parseInt(numString.substring(numString.indexOf('.') + 1)) === 0
        ? Math.floor(number / ranges[index].divider).toString()
        : numString;
    newValue = numString + ranges[index].suffix;
  }
  return newValue;
};

// Input 50000
// Output 50k
// Input 4500
// Output 4.5k

注意:除kilo之外,所有前缀均为大写。比较en.wikipedia.org/wiki/Unit_prefix
Wiimm

哦谢谢!实际上,我的用例需要用小写字母表示一切。
瑞沙伯

0

用作数字原型

为方便而直接。简单地制作一个原型。这是一个例子。

Number.prototype.abbr = function (decimal = 2): string {
  const notations = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
    i = Math.floor(Math.log(this) / Math.log(1000));
  return `${parseFloat((this / Math.pow(1000, i)).toFixed(decimal))}${notations[i]}`;
};

0

印度货币格式为(K,L,C)千,十万,克罗

const formatCash = n => {
  if (n < 1e3) return n;
  if (n >= 1e3 && n < 1e5) return +(n / 1e3).toFixed(1) + "K";
  if (n >= 1e5 && n <= 1e6) return +(n / 1e5).toFixed(1) + "L";
  if (n >= 1e6 && n <= 1e9) return +(n / 1e7).toFixed(1) + "C";
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.