주어진 바이트 수를 사람이 읽을 수있는 형식으로 포맷


16

도전과 기원

스택 오버플로에서 인기있는 질문은 다음과 같습니다. java에서 바이트 크기를 사람이 읽을 수있는 형식으로 변환하는 방법무엇입니까? 가장 많이 투표 된 답변에는이 작업을 수행하는 데 매우 유용한 방법이 있지만 이것이 코드 골프이며 더 잘할 수 있습니까?

주어진 바이트 수를 사람이 읽을 수있는 올바른 형식으로 처리하고 결과를 사용자 언어로 표준에 인쇄하는 방법이나 프로그램을 작성하는 것이 어렵습니다. *

* 자세한 설명은 규칙을 참조하십시오!

입력

입력은 항상 최대 (2 ^ 31) -1의 양의 바이트 수입니다.

산출

국제 단위 시스템 또는 이진 표기법을 출력으로 선호하는 경우 선택할 수 있습니다 (SI 표기법으로 인해 일부 바이트가 절약 될 수 있음).

SI:      B, kB,  MB,  GB  
Binary:  B, KiB, MiB, GiB

참고 : 제한된 입력 범위로 인해 GB 또는 GiB보다 높은 단위는 사용할 수 없습니다.

출력 예

국제 단위 시스템 :

Input       Output
0           0.0     B
999         999.0   B
1000        1.0     kB
1023        1.0     kB
1024        1.0     kB
1601        1.6     kB
160581      160.6   kB
4066888     4.1     MB
634000000   634.0   MB
2147483647  2.1     GB

이진 :

Input       Output
0           0.0     B
999         999.0   B
1000        1000.0  B
1023        1023.0  B
1024        1.0     KiB
1601        1.6     KiB
160581      156.8   KiB
4066888     3.9     MiB
634000000   604.6   MiB
2147483647  2.0     GiB

규칙

  • 바이트 포맷을위한 내장 함수는 허용되지 않습니다!
  • 출력은 항상 동일한 표기법 표준이어야합니다. SI 또는 이진을 혼합해서는 안됩니다.
  • 결과 숫자가 여전히 1보다 크거나 같은 경우 출력은 항상 가능한 최대 단위 여야합니다.
  • 출력은 항상 하나의 십진수를 가져야하지만 결과 출력이 바이트 (B) 일 때 정수를 인쇄하도록 선택할 수 있습니다.
  • 숫자와 단위 사이에 공백, 탭 또는 아무것도 추가하지 않을 것인지 선택할 수 있습니다.
  • STDIN 또는 기능 매개 변수를 통해 입력이 수신됩니다.
  • 출력은 콘솔에 인쇄되거나 문자열 (또는 유사한 문자 컨테이너)로 리턴됩니다.
  • 이것은 코드 골프이므로 최단 답변이 이깁니다. 즐기세요!

편집 : 더 많은 설명

일부 숫자는 숫자 999950과 같은 흥미로운 반올림 동작을 갖습니다. 대부분의 코드 구현은 1.0MB 대신 1000.0 kB를 반환합니다. 왜? 999950/1000은 999.950으로 평가되기 때문에 Java에서 String.format을 사용할 때 1000.0으로 효과적으로 반올림됩니다 (대부분의 다른 언어에서도). 이와 같은 경우를 처리하기 위해 추가 점검이 필요합니다.

이 과제에서는 마지막 스타일이 선호되지만 두 스타일 모두 1000.0 kB 및 1.0 MB가 허용됩니다.

의사 코드 / 자바 테스트 코드 :


public static String bytesToSI(long bytes){
      if (bytes < 1000){
          return bytes + ".0 B";
      }
      //Without this rounding check:
      //999950    would be 1000.0 kB instead of 1.0 MB
      //999950000 would be 1000.0 MB instead of 1.0 GB
      int p = (int) Math.ceil(Math.log(bytes) / Math.log(1000));
      if(bytes/Math.pow(1000, p) < 0.99995){
          p--;
      }
      //Format
      return String.format("%.1f %sB", bytes/Math.pow(1000, p), "kMGTPE".charAt(p-1));
}


1
기술적으로 SI 킬로바이트는 kB소문자 k를 사용해야합니다.
SuperJedi224 2016 년

좋은 지적, 고정!
Rolf ツ

1
많이 제한하고 싶지 않으므로 간격이 일치하지 않을 수 있습니다. 그러나이 규칙 : 초과 할 수 없습니다 다른 유효한 입력을위한 공간과 탭 문자의 차이 (10) (모든 비트 "사람이 읽을 수"를 유지하기 위해)
롤프ツ

2
에 대한 예상 출력 무엇 9999991000000? 160581전시 반올림, 그래서해야 1000.0kB하고 1.0MB?
Sp3000

3
@ Sp3000 좋은 질문입니다. 999999가 1.0MB를 표시하는 것이 가장 좋은 해결책입니다. 그러나이 도전에 대해서는 1000.0 KB와 비슷한 반올림 사례도 좋습니다.
Rolf ツ

답변:


10

TI-BASIC, 44

TI-BASIC이 중간 정도의 문자열 조작을 가지고 있다면 작업에 적합한 도구가 될 것입니다 (엔지니어링 표기법으로 표시된 숫자의 지수를 단위로 덮어 써야했습니다). 그대로 반올림하고 올바르게 출력하지만 우승 항목에 가깝지는 않습니다. 다른 계산기 언어가이 언어에서 이길 수 있을까요?

Fix 1
Eng
ClrHome
Disp Ans
Output(1,15,sub(" kMG",1+iPart(log(Ans+.5)/3),1)+"B

[number]:[program name]홈 화면에 양식 으로 입력하십시오 .

주어진 테스트 사례 :

Input       Output (leading spaces intentional; screen clear before each output)
0                      0.0 B
999                  999.0 B
1000                   1.0kB
1023                   1.0kB
1024                   1.0kB
1601                   1.6kB
160581               160.6kB
4066888                4.1MB
634000000            634.0MB
2147483647             2.1GB

나는 TI-BASIC 하하 다양한 너무 것을 전혀 생각이 없었다
베타 붕괴를

1
TI-BASIC은 다재다능하지 않지만 몇 가지 단점에 대한 이상한 해결 방법이 종종 있습니다.
lirtosiast 2016 년

6

CJam, 35 27 바이트

ri{_e-3_i}g;1mOo]," kMG"='B

8 바이트를 제거해 주셔서 감사합니다.

이 인쇄되지 않습니다 .0에서 온라인 인터프리터 . 그러나 Dennis가 지적했듯이 Java 인터프리터에서 잘 작동합니다.

설명

ri         e# Read the input as an integer.
{          e# Do:
    _e-3   e#   Make a copy and divide by 1000.
           e#   This will generate one more item in the stack for each iteration.
    _i     e#   Make a copy and truncate to integer.
}g         e# until the integer part is 0.
;          e# Discard the final value with integer part 0.
1mOo       e# Output the number before it with the correct format.
],         e# Count the number of iterations - 1.
" kMG"=    e# Select a character according to the number of iterations.
'B         e# Output B.

ri{_e-3XmO_i}g;o]," kMG"='B(27 바이트)
Dennis

@Dennis 감사합니다 1mO. 그러나이 코드는 작동하지 않습니다 1149999...
jimmy23013

ri{_e-3_i}g;1mOo]," kMG"='B할까요.
Dennis

스크래치하면 다른 버그가 있습니다.
Dennis

999999됩니다 1000kB. 질문을 다시 읽으면 1000kB실제로 잘못된 것인지 확실하지 않습니다 .
Dennis

5

Pyth, 29 27 바이트

p@" kMG"Js.lQK^T3.RcQ^KJ1\B

데모. 테스트 하네스.

설명:

p@" kMG"Js.lQK^T3.RcQ^KJ1\B
                                 Implicit: Q = eval(input())
p                                print, in the order 2nd arg then 1st arg:
             K^T3                K = 10^3 = 1000
          .lQK                   log of Q base K
         s                       Floored
        J                        Store to J
 @" kMG"J                        The Jth character of ' kMG'
                     ^KJ         K^J
                   cQ            Q/K^J (Floating point division)
                 .R     1        Round to 1 decimal place.
                         \B      Print a trailing 'B'.

3

CJam, 28

r_dA@,(3/:X3*#/1mO" kMG"X='B

온라인으로 사용해보십시오

참고 : 온라인 통역사에는 ".0"이 표시되지 않지만 공무원에게는 표시됩니다. Java 인터프리터에서는 표시 됩니다.

설명:

r_          read and duplicate
dA          convert to double and push 10
@           bring the initial string to the top
,(          get the length and decrement
3/          divide by 3 (for thousands)
:X3*        store in X and multiply by 3 again
#           raise 10 to that power
/           divide the original number by it
1mO         round to 1 decimal
" kMG"X=    convert X from 0/1/2/3 to space/k/M/G
'B          add a 'B'

백틱은 무엇입니까?
Dennis

온라인 통역사에서 .0을 보여주는
@Dennis

백틱없이 Java 인터프리터에서 제대로 작동하므로 필요하다고 생각하지 않습니다.
데니스

3

파이썬 2-76 바이트

당신의 머리 속에서하기가 더 쉽기 때문에 단위의 국제 시스템을 사용합니다;)

n=input();m=0;f=1e3
while n>=f:n/=f;m+=2
print"%.1f%s"%(n,'B kBMBGB'[m:m+2])

"2147483647"을 제출하면 예를 들어, 요청 된 형식을 존중하지 않습니다. 예를 들어 "2.000000GB"를 얻습니다.이 질문은 소수점 이하 자릿수와 공백을 요구합니다.
Dieter

1
또한, 이것에 따라 79 바이트 . 이것은 75 바이트입니다. 나는 숫자와 단위 사이에 공백이 있어야한다고 지정되지 않았다.
Kade

당신은 1 바이트를 절약 할 수 있습니다f=1e3
mbomb007

1e3는 부동이기 때문에 @ mbomb007 실제로는 2 바이트를 저장
베타 붕괴를

나는 그것이 부유물이라는 것을 알고 있었다. 난 그냥 셀 수없는 것 같아요 ...
mbomb007

2

파워 쉘, 190

$x=Read-Host
function f($a,$b){"$x`t"+[math]::Round($x/$a,1).ToString("F1")+"`t$b"}
if(1KB-gt$x){f 1 "B"}elseif(1MB-gt$x){f 1KB KiB}
elseif(1GB-gt$x){f 1MB MiB}elseif(1TB-gt$x){f 1GB GiB}

용법

PS C:\> .\makehum.ps1
1601
1601    1.6     KiB
PS C:\> .\makehum.ps1
4066888
4066888 3.9     MiB
PS C:\> .\makehum.ps1
160581
160581  156.8   KiB
PS C:\> .\makehum.ps1
634000000
634000000       604.6   MiB
PS C:\> .\makehum.ps1
2147483647
2147483647      2.0     GiB
PS C:\>

2

하스켈, 119

슬프게도 Haskell에서 소수점 이하 1 자리를 수레로 만드는 짧은 방법을 찾지 못했지만 후손을 위해 게시하고 있습니다.

import Text.Printf
a#n|p>=1=(a+1)#p|1<2=(a,n)where p=n/1000
m n=let(a,b)=0#n in printf"%.1f"b++["B","kB","MB","GB"]!!a

용법:

> m 160581
"160.6kB"

적당히 덜 골프 버전 :

import Text.Printf

countThousands :: Int -> Float -> (Int, Float)
countThousands count num
 |nextNum >= 1 = countThousands (count+1) nextNum
 |otherwise    = (count,num)
 where nextNum = num/1000

printHuman :: Float -> String
printHuman n = let (a,b) = countThousands 0 n in 
  (printf "%.1f" b) ++ (["B","kB","MB","GB"]!!a)

2

자바, 106 바이트

이것은 숫자를 취하고 문자열을 반환하는 메소드입니다.

String f(int n){int k=0;for(;n>1e3;k++)n/=1e3;return(int)(10*n)/10.0+new String[]{"","k","M","G"}[k]+"B";}

완전한 프로그램 대신 문자열을 반환하는 함수를 프로그래밍 할 수 있습니다. 일부 바이트를 절약 할 수 있습니다.)
Rolf ツ

세 가지 : 당신은 이중 어쨌든로 변환하는 경우, 당신은 사용할 수 있습니다 (이 필요하다면 나도 몰라) 1e3에 대한 1000; while()이것을 a 로 변환 for()하고 무료 세미콜론을 사용할 수 있습니다. 그리고 이것이 작동하는지 모르겠습니다. 소수점을 지나서 한 자리가 아닌 모든 소수점을 표시하는 것 같습니다.
lirtosiast 2016 년

@ ThomasKwa : 마지막으로 확인했지만 질문에 명시 적으로 지정되지 않은 것 같습니다. 그러나 지금은 그렇게 생각합니다.
SuperJedi224

1

파이썬 2, 127 바이트

ISU 사용 이 스 니펫은 숫자를 인수로 변환하는 함수 'C'를 선언합니다.

C=lambda v:min(['%.1f %sB'%(x,u)for x,u in[(v/1000.0**i,'bkMG'[i])for i in range(4)]if x>=1]).replace('.0 b',' ')if v else'0 B'

일부 테스트 코드 :

    print 'Input\tOutput'
for v in [0,999,1000,1023,1023,1601,160581,4066888,634000000,2147483647]:
 print v,C(v)

1e3대신 사용할 수 있습니다1000.0
mbomb007

1

자바 스크립트 ( ES6 ), 71

SI 단위 사용-요청 된 문자열을 반환하는 함수입니다.

f=(a,b=3)=>+(r=eval('a/1e'+b*3).toFixed(1))[0]?r+' kMG'[b]+'B':f(a,b-1)

이 짧은 것은 특히 3과 4의 규칙을 따릅니다

  • 결과 숫자가 여전히 1보다 크거나 같은 경우 출력은 항상 가능한 가장 큰 단위 여야합니다. 995 => 1.0kB
  • 출력은 항상 하나의 십진수를 가져야하지만 결과 출력이 바이트 (B) 일 때 정수를 인쇄하도록 선택할 수 있습니다. 그렇지 않기 때문에 10 => 10.0 B

아아, 이런 식으로 결과가 예제와 일치하지 않습니다.

예제와 일치시키기 위해 여기에 더 긴 숫자가 있으며 작은 숫자 (82 바이트)에 대해 특수한 경우입니다

f=(a,b=3)=>a<1e3?a+'B':+(r=eval('a/1e'+b--*3).toFixed(1))[0]?r+'kMG'[b]+'B':f(a,b)

테스트 할 스 니펫 실행 (EcmaScript 6, Firefox 만 해당)


1

파이썬, 61 바이트

f=lambda n,i=0:"%.1f%cB"%(n," kMG"[i])*(n<1e3)or f(n/1e3,i+1)

처럼 전화하십시오 f(999). 참고 1e3부동, 그래서 모두 파이썬 2와 파이썬 3이 작동합니다.


1

PHP4.1, 63 62 바이트

최고의 골프는 아니지만 확실히 짧습니다.

<?for($S=kMG;$B>1e3;$I++)$B/=1e3;printf("%.1f{$S[$I-1]}B",$B);

사용하려면 POST / GET을 통해 액세스하거나 키의 세션에서 값을 설정하십시오. B .

키를 I설정하지 않은 상태로 두십시오 !


1

SpecBAS-100 바이트

ISU 규칙 사용

변수를 1e3 (변수를 할당하려면 LET 문이 필요함)으로 설정 한 다음 운동에서 해당 변수를 사용하면 실제로 1e3을 하드 코딩하는 것보다 더 많은 문자를 실제로 사용한다는 것을 알았습니다.

1 INPUT n: LET i=1
2 DO WHILE n>1e3: LET n=n/1e3: INC i: LOOP 
3 PRINT USING$("&.*0#",n);" kMG"(i);"B"

1

루비, 128 바이트

c=->i{p i.to_s+'B'if i<1e3;p (i/1e3).to_s+'kB'if i>=1e3&&i<1e6;p (i/1e6).to_s+'MB'if i>=1e6&&i<1e9;p (i/1e9).to_s+'GB'if i>=1e9}

나는 먼 길을 갔다, 이것은 꽤 나쁘다.

산출

c[0] # => "0B"
c[999] # => "999B"
c[1000] # => "1.0kB" 
c[1023] # => "1.023kB"
c[1024] # => "1.024kB"
c[1601] # => "1.601kB"
c[160581] # => "160.581kB"
c[4066888] # => "4.066888MB"
c[634000000] # => "634.0MB"
c[2147483647] # => "2.147483647GB"

편집하다

추가 39 바이트에 TB 추가

c=->i{p i.to_s+'B'if i<1e3;p (i/1e3).to_s+'kB'if i>=1e3&&i<1e6;p (i/1e6).to_s+'MB'if i>=1e6&&i<1e9;p (i/1e9).to_s+'GB'if i>=1e9&&i<1e12;p (i/1e12).to_s+'TB'if i>=1e12}

산출:

c[1000000000000] # => "1.0TB"

1

Sed -r, 218 + 1

SI 단위를 사용하고 있습니다. 바이너리 단위를 선택 하는 것은 용기있는 정책 이라고 생각합니다 . ;-)

s/(.)((...)+)$/\1z\2/;h;s/[^z]*z?//;s/.../k/g;s/kk/M/;s/Mk/G/;x;s/(z.)[5-9].*/\1c/;s/(z.c?).*/\1/;:;s/9c/c0/;s/zc/cz/;t;s/(^|0)c/1/;s/1c/2/;s/2c/3/;s/3c/4/;s/4c/5/;s/5c/6/;s/6c/7/;s/7c/8/;s/8c/9/;G;s/\n//;s/$/B/;y/z/./

재 포맷 :

#!/bin/sed -rf

# Place decimal point (use z as shorthand for \.)
s/(.)((...)+)$/\1z\2/
h

# count thousands into hold space
s/[^z]*z?//
s/.../k/g
s/kk/M/;s/Mk/G/
x

# truncate to 1 decimal place
s/(z.)[5-9].*/\1c/
s/(z.c?).*/\1/

# propagate carry
:
s/9c/c0/
s/zc/cz/
t
s/(^|0)c/1/
s/1c/2/
s/2c/3/
s/3c/4/
s/4c/5/
s/5c/6/
s/6c/7/
s/7c/8/
s/8c/9/

# Append units
G;s/\n//
s/$/B/
y/z/./

산출

1 => 1B
9 => 9B
99 => 99B
999 => 999B
1000 => 1.0kB
9999 => 10.0kB
99949 => 99.9kB
99950 => 100.0kB
99999 => 100.0kB
999999 => 1000.0kB
9999999 => 10.0MB
9999999999 => 10.0GB
1000 => 1.0kB
10000 => 10.0kB
10005 => 10.0kB
10440 => 10.4kB
10450 => 10.5kB
10950 => 11.0kB

변형

규칙은 가장 가까운 것을 의미하는 것처럼 보이지만 사람이 표시하려면 반올림이 허용되는 대안이며 123 바이트를 절약합니다 (50 % 미만).

s/(.)((...)+)$/\1.\2/;h;s/[^\.]*\.?//;s/.../k/g;s/kk/M/;s/Mk/G/;x;s/(\..).*/\1/;G;s/\n//;s/$/B/

더 큰 단위로 자연스럽게 확장 (여전히 반올림, 130 + 1 바이트) :

s/(.)((...)+)$/\1.\2/;h;s/[^\.]*\.?//;s/.../k/g;s/kk/M/g;s/Mk/G/;s/MM/T/g;s/TT/Y/;s/TM/E/;s/TG/Z/;x;s/(\..).*/\1/;G;s/\n//;s/$/B/

변형 출력 :

1 => 1B
9 => 9B
99 => 99B
999 => 999B
1000 => 1.0kB
9999 => 9.9kB
99949 => 99.9kB
99950 => 99.9kB
99999 => 99.9kB
999999 => 999.9kB
9999999 => 9.9MB
9999999999 => 9.9GB
1000 => 1.0kB
10000 => 10.0kB
10005 => 10.0kB
10440 => 10.4kB
10450 => 10.4kB
10950 => 10.9kB
1000000000 => 1.0GB
1000000000000 => 1.0TB
1000000000000000 => 1.0MGB
1000000000000000000 => 1.0EB
1000000000000000000000 => 1.0ZB
1000000000000000000000000 => 1.0YB
999999999999999999999999999 => 999.9YB

잘 했어! 나는 당신이 모든 다른 옵션에 대해 생각한 것을 좋아합니다!
Rolf ツ

1

C, 77 75

f(float l){char*u=" kMG";while((l/=1e3)>=1)++u;printf("%.1f%cB",l*1e3,*u);}

SI 단위를 사용하고 반올림에 1000.0kB 옵션을 사용합니다.

확장 코드 :

f(float l)
{
    char *u = " kMG";
    while ((l/=1000) >= 1)
        ++u;
    printf("%.1f%cB", l*1000, *u);
}

산출

9 => 9.0 B
9999 => 10.0kB
1023 => 1.0kB
1024 => 1.0kB
999990 => 1000.0kB
1048575 => 1.0MB
1048576 => 1.0MB
2147483647 => 2.1GB

변형

이진 단위 변경 얻으려면 1000까지를 1024, 그리고 추가 i승수가 있다면 포맷 문자열. 4 자리 반올림을 피하려면 >=.95대신 대신 비교하십시오 >=1. 더 큰 단위를 사용하려면 u문자열을 확장하십시오 . 이러한 모든 옵션을 결합하면 다음과 같은 이점이 있습니다.

f(float l)
{
    char*u=" kMGTPEZY";
    while((l/=1024)>=.95)++u;
    printf(*u-' '?"%.1f%ciB":"%.0fB",l*1024,*u);
}

변형 출력

9 => 9B
9999 => 9.8kiB
1023 => 1.0kiB
1024 => 1.0kiB
999990 => 1.0MiB
1048575 => 1.0MiB
1048576 => 1.0MiB
2147483647 => 2.0GiB
1000000000 => 953.7MiB
1000000000000 => 931.3GiB
1000000000000000 => 909.5TiB
1000000000000000000 => 888.2PiB
1000000000000000000000 => 867.4EiB
1000000000000000000000000 => 847.0ZiB
999999999999999999999999999 => 827.2YiB
1176043059457204080886151645 => 972.8YiB

테스트 프로그램

명령 줄 인수로 여러 입력을 전달하십시오.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    while (*++argv) {
        printf("%s => ", *argv);
        f(strtod(*argv, 0));
        puts("");
    }
    return 0;
}

좋은 하나;) 잘 실행!
Rolf ツ

0

루비, 91 바이트

n=gets.to_i;i=0;while n>1023;n/=1024.0;i+=1;end;puts "#{n.round 1} #{%w[B KiB MiB GiB][i]}"

내가 더 열심히 노력한다면 아마 조금 더 잘할 수 있지만 여기에 내가 가진 것들이 있습니다.


1024.대신에 사용하십시오 1024.0.
mbomb007

0

자바 스크립트 ES5, 69 바이트

이것은 @ edc65 's answer 의 최종 목표에 도달하기 위해 다른 방법을 사용합니다 .
실제로 이것은 내 PHP 답변과 매우 비슷합니다 .

for(i=+prompt(z=0);i>1e3;z++)i/=1e3;alert(i.toFixed(1)+' kMG'[z]+'B')

스택 스 니펫을 실행하거나 콘솔에 붙여 넣기 만하면됩니다.


0

루비, 90 바이트

proc{|n|q=((1..3).find{|i|n<(1<<i*10)}||4)-1;[n*10/(1<<q*10)/10.0,%w[B kB MB GB][q]].join}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.