Verilen bayt sayısını insan tarafından okunabilir bir formatta biçimlendirin


16

Meydan okuma ve köken

Stack Overflow'da popüler bir soru şudur: Bayt boyutunu java'da okunabilir biçime nasıl dönüştürebilirim? En çok oylanan cevabın bunu yapmak için oldukça güzel bir yöntemi var, ancak bu kodgolf ve daha iyisini yapabiliriz, değil mi?

Zorluğunuz, verilen bayt sayısını doğru okunabilir formata dönüştüren ve sonucu kendi dilinizden standart olarak basan bir yöntem veya program yazmaktır. *

* Daha fazla açıklama için kurallara bakınız!

Giriş

Giriş her zaman en fazla (2 ^ 31) -1 ile pozitif bir bayt sayısı olacaktır.

Çıktı

Çıktı olarak Uluslararası Birimler Sistemini mi yoksa ikili gösterimi mi tercih edeceğinizi seçebilirsiniz (SI notasyonu muhtemelen size bazı bayt kazandırır).

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

Not: Kısıtlı giriş aralığı nedeniyle GB veya GiB'den daha yüksek birimler mümkün değildir.

Örnek çıktı

Uluslararası Birimler Sistemi:

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

İkili:

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

kurallar

  • Bayt biçimlendirmesi için yerleşik işlevlere izin verilmez!
  • Çıktı her zaman aynı gösterim standardında olmalıdır, SI veya ikili karıştırılamaz;
  • Çıktı her zaman elde edilen sayı hala bir veya daha yüksek olduğunda mümkün olan en büyük birimde olmalıdır;
  • Çıktının her zaman bir ondalık sayı olması gerekir, ancak sonuçta elde edilen çıktı bayt (B) cinsindeyken bir tam sayı yazdırmayı seçebilirsiniz;
  • Sayı ve birim arasına boşluk, sekme veya hiçbir şey eklemek isteyip istemediğinizi seçebilirsiniz;
  • Giriş STDIN veya fonksiyon parametreleri aracılığıyla alınır;
  • Çıktı konsola yazdırılır veya dize (veya benzer karakter kabı) olarak döndürülür;
  • Bu kod golf, bu yüzden en kısa cevap kazanır. İyi eğlenceler!

Düzenleme: Daha fazla açıklama

Bazı sayılar 999950 sayısı gibi ilginç yuvarlama davranışlarına sahiptir. Çoğu kod uygulaması 1,0 MB yerine 1000,0 kB döndürür. Neden? Çünkü 999950/1000, Java'da String.format kullanırken (diğer birçok dilde) etkili bir şekilde 1000.0'a yuvarlanan 999.950 olarak değerlendirilir. Hench, bu gibi davaları ele almak için bazı ekstra kontrollere ihtiyaç vardır.

Bu meydan okuma için her iki stil de 1000.0 kB ve 1.0 MB kabul edilir, ancak son stil tercih edilir.

Sahte kod / java test kodu:


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
Teknik olarak, SI kilobayt kullanmalıdır kB(küçük harf k'ye dikkat edin)
SuperJedi224

İyi nokta, sabit!
Rolf ツ

1
Çok sınırlamak istemiyorum, bu yüzden aralığın tutarsız olabileceğini söyleyebilirim. Ancak bu kural ile: Farklı geçerli girişler için boşluk ve sekme karakterleri arasındaki fark 10'u geçemez. (Her şeyi biraz "insan tarafından okunabilir" tutmak için)
Rolf ツ

2
İçin beklenen çıkış nedir 999999ve 1000000? 160581yuvarlama sergiler, öyle olmalı 1000.0kBve 1.0MB?
Sp3000

3
@ Sp3000 Bu iyi bir soru, en güzel çözüm 999999 için 1.0 MB görüntülemek olacaktır. Ancak bu meydan okuma için 1000.0 KB ve benzeri yuvarlama vakalarının da iyi olduğunu söyleyebilirim.
Rolf ツ

Yanıtlar:


10

TI-BASIC, 44

TI-BASIC'in yarısı iyi dize manipülasyonu olsaydı iş için doğru araç olurdu (mühendislik gösteriminde görüntülenen sayının üssünün üzerine yazmak için başvurmak zorunda kaldım). Olduğu gibi düzgün bir şekilde yuvarlanır ve çıkar, ancak kazanan girişlere bile yakın değildir. Belki farklı bir hesap makinesi dili bunu kazanabilir?

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

[number]:[program name]Ana ekranda forma girin .

Verilen test durumları:

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'in çok yönlü olduğu konusunda hiçbir fikrim yoktu haha
Beta Çürümesi

1
TI-BASIC çok yönlü değildir, ancak bazı eksiklikleri için garip çözümler vardır.
lirtosiast

6

CJam, 35 27 bayt

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

Dennis 8 baytı kaldırdığınız için teşekkürler.

Bu .0, çevrimiçi yorumlayıcıda yazdırılmaz . Ancak Dennis'in belirttiği gibi , Java yorumcusunda iyi çalışıyor.

açıklama

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 bayt)
Dennis

@Dennis 1mO. İçin teşekkürler . Ancak bu kod işe yaramıyor 1149999...
jimmy23013

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

Çizik, başka hataları var.
Dennis

999999olur 1000kB. Soruyu tekrar okuduğumda, 1000kByanlış olup olmayacağından emin değilim .
Dennis

5

Pyth, 29 27 bayt

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

Gösteri. Test Donanımı.

Açıklama:

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

Çevrimiçi deneyin

Not: çevrimiçi yorumlayıcı ile ".0" göstermez, ancak resmi java yorumlayıcıyla bunu gösterir .

Açıklama:

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'

Backtick ne için?
Dennis

@Dennis online yorumlayıcıda .0 gösteriliyor
aditsu quit çünkü SE

Java yorumlayıcısında backtick olmadan iyi çalışıyor, bu yüzden ihtiyacınız olduğunu düşünmüyorum.
Dennis

3

Python 2-76 bayt

Ünitelerin İnternasyon Sistemini kullanır, çünkü kafanızda yapmak daha kolaydır;)

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

benim için iyi görünmüyor, "2147483647" Ben "2.000000GB" elde edersem örnek için sorulan biçimlendirmeye saygı duymaz - Soru bir ondalık ve belki bir boşluk ister.
Dieter

1
Ayrıca, buna göre 79 bayt bu . Bu 75 bayt. Sayı ile birim arasında boşluk olması gerektiğine inanmıyorum.
Kade

ile bir bayt kaydedebilirsinizf=1e3
mbomb007

@ mbomb007 1e3 bir şamandıra olduğu için aslında 2 bayt kurtardı
Beta

Bunun bir şamandıra olduğunu biliyordum. Sanırım sadece
sayamıyorum

2

PowerShell, 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}

kullanım

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

Haskell, 119

Ne yazık ki Haskell'de şamandıralarda 1 ondalık basamak sağlamak için daha kısa bir yol bulamadım, ancak gelecek kuşaklar için gönderiyorum.

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

Kullanımı:

> m 160581
"160.6kB"

Kısmen daha az golf versiyon:

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

Java, 106 bayt

Bu, bir sayı alan ve bir dize döndüren bir yöntemdir.

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

Tam bir program yerine dize döndüren bir işlevi programlamanıza izin verilir, size bazı baytlar kaydedebilir;)
Rolf ツ

Üç şey: Eğer zaten bir çifte dönüştürüyorsanız (gerekli olup olmadığını bilmiyorum), 1e3için kullanabilirsiniz 1000; bunu while()a dönüştürebilir for()ve ücretsiz noktalı virgülleri kullanabilirsiniz; ve bunun işe yarayıp yaramadığını bilmiyorum, çünkü ondalık basamaktan sadece bir tanesini değil tüm ondalık basamakları gösteriyor gibi görünüyor.
lirtosiast

@ThomasKwa: Son kontrol ettiğimde, soru bunu açıkça belirtmedi. Ama sanırım şimdi öyle.
SuperJedi224

1

Python 2, 127 bayt

ISU'yu kullanma. Parçacık, bağımsız değişken olarak dönüştürülecek sayıyı alan bir 'C' işlevini bildirir.

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'

Bazı test kodları:

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

Bunun 1e3yerine kullanabilirsiniz1000.0
mbomb007

1

JavaScript ( ES6 ), 71

SI birimlerini kullanma - İstenen dizeyi döndüren bir işlev.

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

Bu daha kısa kural, özellikle 3 ve 4 kurallarına uyar

  • Çıktı her zaman elde edilen sayı hala bir veya daha yüksek olduğunda mümkün olan en büyük birimde olmalıdır. 995 => 1.0kB
  • Çıktının her zaman bir ondalık sayı olması gerekir, ancak sonuçta elde edilen çıktı bayt cinsindeyken bir tamsayı yazdırmayı seçebilirsiniz (B) Seçmiyorum , bu nedenle 10 => 10.0 B

Ne yazık ki, bu şekilde, sonuçlar örneklerle eşleşmiyor.

Örneklerle eşleşmek için, daha küçük bir sayı (82 bayt) için özel, daha uzun olanı

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

Test etmek için snippet'i çalıştırın (yalnızca EcmaScript 6, Firefox olarak)


1

Python, 61 bayt

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

Gibi arayın f(999). Bunun 1e3bir kayan nokta olduğuna dikkat edin , bu hem Python 2 hem de Python 3 ile çalışır.


1

PHP4.1, 63 62 bayt

En iyi golf değil, ama kesinlikle oldukça kısa.

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

Bunu kullanmak için POST / GET üzerinden erişin veya tuşun üzerindeki OTURUM'da bir değer ayarlayın B.

Anahtarı Iayarlanmamış bırakın !


1

SpecBAS - 100 bayt

ISU sözleşmesini kullanma.

Ben 1e3 (bu atamak için bir LET deyimi gerekir) bir değişkene sahip olduğunu ve daha sonra bu değişkeni çalışma dışarı kullanarak, aslında sadece gerekli 1e3 sabit kodlama daha fazla karakter kullandığını fark ettim.

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

Yakut, 128 bayt

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}

Uzun yoldan yaptım, bu oldukça kötü.

Çıktı

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"

Düzenle

Fazladan 39 bayt için TB eklendi

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}

Çıktı:

c[1000000000000] # => "1.0TB"

1

Sed -r, 218 + 1

SI birimleri kullanıyorum; İkili birimlerin seçilmesinin cesur bir politika olacağını düşünüyorum . ;-)

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

reformasyon:

#!/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/./

Çıktı

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

Varyasyonlar

Kurallar en yakın yuvarlama anlamına geliyor gibi görünüyor, ancak insan teşhirinde, aşağı yuvarlamanın kabul edilebilir bir alternatif olduğuna inanıyorum ve 123 bayt (% 50'den daha iyi) kurtarıyor:

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

Daha büyük birimlere doğal uzatma (hala yuvarlanıyor, 130 + 1 bayt):

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/

Varyasyon çıktısı:

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

İyi iş! Tüm farklı seçenekleri düşündüğünü sevdim!
Rolf ツ

1

C, 77 75

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

Bu SI birimlerini kullanır ve yuvarlama için 1000.0kB seçeneğini kullanır.

Genişletilmiş kod:

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

Çıktı

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

Varyantlar

İkili birimleri, değişim elde etmek 1000için 1024, ve eklemek ibir çarpan olmadığını biçim dizesine. 4 basamaklı yuvarlamayı önlemek için >=.95yerine karşılaştırın >=1. Daha büyük birimleri kabul etmek için udizeyi uzatın . Tüm bu seçenekleri birleştirerek şunları elde ederiz:

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

Değişken çıktı

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

Test programı

İstediğiniz sayıda girişi komut satırı bağımsız değişkeni olarak iletin:

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

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

Güzel bir;) Aferin!
Rolf ツ

0

Ruby, 91 bayt

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

Daha çok denersem muhtemelen biraz daha iyi yapabilirdim ama işte şimdiye kadar aldım.


Yerine 1024.kullanın 1024.0.
mbomb007

0

Javascript ES5, 69 bayt

Bu, @ edc65'in cevabındaki nihai hedefe ulaşmak için farklı bir yol kullanır .
Aslında, bu benim PHP cevap oldukça yakın .

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

Yığın snippet'ini çalıştırın veya bunu konsolunuza yapıştırın.


0

Ruby, 90 bayt

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}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.