자바 스크립트에서 긴 숫자를 축약 된 문자열로 변환합니다.


82

JavaScript에서 주어진 [edit : positive integer ] 숫자 (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는 아니지만 Gist.github.com/1870641 에서 볼 수있는 C ++에서 동일한 작업을 수행했습니다 . 프로세스는 동일합니다. 하지만 기성 솔루션을 찾는 것이 더 나을 수 있습니다.
csl

Baz, 내 현재 시작은 언급 된 문제와 함께 연결된 스레드에서 약간 재구성 된 함수입니다. 그 기능을 향상시키기 전에 다른 누군가가 이미 어딘가에 스마트 기능을 작성했거나 쉽게 수행하는 방법을 알고 있기를 바랐습니다. Csl, 좋습니다. 감사합니다! 그 변환은 또한 언급 된 "0.1m"스타일을 수행합니까?
Philipp Lenssen


9
뭐야 shortNum? 당신은 사용하지 않습니다, 그리고 심지어 선언 아니에요 ..
VSYNC

1
또한 사이의 혼합있다 .,그래서 1001.5수백만 대신 수천집니다.
vsync

답변:


63

나는 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에서 올바른 방법이기를 바랍니다. 필요한 경우 변경하십시오). 훌륭한!
Philipp Lenssen

호기심에서 : 어떤 케이스 / 요구 사항을 놓쳤습니까?
chucktator

1
그것들은 사소하고 귀하의 훌륭한 답변에 따라 빠르게 수정되었습니다. 다음 테스트 번호는 약간 누락되었습니다. 123은 0.12k가되었습니다 (이상적인 결과 : 123, 여전히 3 글자이므로 괜찮습니다). 123456은 0.12m가되었습니다 (이상 : 0.1m, 0.12m는 4 글자, 마이너스 도트이므로). 0.12b에 대해서도 동일하며 수정 사항이 있으면 이제 0.1b가됩니다. 도와 주셔서 다시 한 번 감사드립니다!
Philipp Lenssen

1
나는 그것을 약간 조정했습니다 (아직 피어 리뷰를 받기 위해). 나는 value = Math.round (value); 기능의 시작 부분까지. 이렇게하면 "값"에 소수 자리가있을 때 깨지지 않습니다. 10025.26584는 NaN 대신 10k로 바뀝니다
Daniel Tonon

2
shortNum@PhilippLenssen의 마지막 편집에 정의되어 있지 않습니다if (shortValue % 1 != 0) shortNum = shortValue.toFixed(1);
Honza

47

이것은 매우 큰 값도 처리하며 좀 더 간결하고 효율적입니다.

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.

1
훨씬 더 나은 솔루션
Danillo Corvalan 고

감사. 나는 이것을 내 프로젝트에 넣었고 그것은 매력처럼 작동합니다. 굉장한 솔루션, 매우 견고합니다.
spieglio

1
매우 작은 값 (예 5e-18:)의 경우 "0T"를 반환하므로 다음을 추가했습니다.if (num < 1e-3) { return '~0'; }
Paul Razvan Berg

저는 최근에 파이썬에서 같은 문제에 부딪 쳤고 훨씬 더 간단한 접근 방식을 빠르게 생각해 냈습니다 (지난 5 년 동안 제 생각이 바뀌 었다고 생각합니다). 도움이되는 경우 여기에 있습니다. JS에서보고 싶습니다. stackoverflow.com/a/65084005/1438550
D.Deriso

20

이 스레드에 대한 많은 답변은 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
페드로 페레이라

16

여기에 상당히 우아한 솔루션이라고 생각합니다. 음수를 처리하지 않습니다 .

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

나는 k, m, b보다 SI 기호를 더 좋아합니다. 미국 / 영국의 1b는 1e9이지만 다른 많은 국가에서는 1e12입니다.
Christiaan Westerbeek

14

나는 당신이 시도하지 못할 생각 / numeraljs을

당신은 1K 1000 변환하려면

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

123400을 123.4k로 변환하려면 이것을 시도하십시오.

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

환상적인 솔루션 당신은 타사 라이브러리를 설치하고자하는 경우
콜비 콕스

사용 방법이 0.0a있지만 숫자가 1000 일 때 표시 1k하지 1.0k않습니까? (0 트리밍)
Paul Razvan Berg

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

이 스레드에서 위의 모든 솔루션을 시도한 후 올바르게 작동하는 유일한 솔루션입니다. 감사합니다 Danilo!
ty.

3

여기에 또 다른 방법이 있습니다. 123456이 0.1M 대신 123.4K가되기를 원했습니다.

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

이 대답은 훌륭하다고 생각합니다. 선행 0으로 값을 표시하고 싶지 않은 약간 다른 경우가있었습니다. 추가했습니다 if (adjustedValue.charAt (0) === '0') {return adjustValue * 1000 + suffixes [suffixIndex-1]; } else {return adjustValue + suffixes [suffixIndex]; }
user3162553

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

뭔가 잘못 됐어요. 변환기 (824492, 1)는 0.8M을 반환합니다. 824k를 반환해야합니다
Sebastian SALAMANCA

0

Intl은 구현 된 국제화 된 동작을위한 자바 스크립트 표준 '패키지'입니다. 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 제공

관련 질문 : 수천 (1k) 및 수백만 (1m)의 JavaScript에서 현지화 된 숫자를 축약합니다 .


그러나 접미사는 현지화되지 않습니다.
glen-84

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의 경우 k를 제외하고 모든 접두사는 대문자입니다. 비교 en.wikipedia.org/wiki/Unit_prefix
Wiimm

오 감사! 실제로 내 사용 사례에는 소문자로 된 모든 것이 필요합니다.
Rishabh

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) Thousand, Lakh, Crore로

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";
};
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.