Memformat jumlah byte yang diberikan ke format yang dapat dibaca manusia

16

Tantangan dan asal

Pada Stack Overflow, pertanyaan populer adalah: Bagaimana mengubah ukuran byte menjadi format yang dapat dibaca manusia di java? Jawaban terpilih memiliki metode yang cukup bagus untuk melakukan ini, tetapi ini adalah codegolf dan kita bisa melakukan yang lebih baik, bukan?

Tantangan Anda adalah menulis metode atau program yang mencakup jumlah byte yang diberikan ke format yang dapat dibaca manusia dan mencetak hasilnya dengan standar dari bahasa Anda. *

* Lihat aturan untuk klarifikasi lebih lanjut!

Memasukkan

Input akan selalu berupa jumlah positif byte dengan maksimum (2 ^ 31) -1.

Keluaran

Anda dapat memilih jika Anda lebih suka Sistem Satuan Internasional atau notasi biner sebagai output (notasi SI mungkin menghemat beberapa byte).

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

Catatan: Unit yang lebih tinggi dari GB atau GiB tidak dapat dilakukan karena rentang input yang dibatasi.

Contoh output

Sistem Satuan Internasional:

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

Biner:

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

Aturan

  • Fungsi bawaan untuk pemformatan byte tidak diizinkan!
  • Outputnya harus selalu dalam standar notasi yang sama, Anda tidak boleh mencampur SI atau biner;
  • Output harus selalu dalam unit terbesar yang mungkin di mana jumlah yang dihasilkan masih lebih tinggi atau sama dengan satu;
  • Output harus selalu memiliki satu angka desimal, tetapi Anda dapat memilih untuk mencetak angka integer ketika output yang dihasilkan dalam byte (B);
  • Anda dapat memilih apakah Anda ingin menambahkan spasi, tab atau tidak sama sekali antara angka dan unit;
  • Input diterima melalui STDIN atau parameter fungsi;
  • Output dicetak ke konsol atau dikembalikan sebagai string (atau wadah karakter serupa);
  • Ini kode golf, jadi jawaban tersingkat menang. Selamat bersenang-senang!

Sunting: Klarifikasi lebih lanjut

Beberapa angka memiliki perilaku pembulatan yang menarik seperti angka 999950. Sebagian besar implementasi kode akan mengembalikan 1000,0 kB, bukan 1,0 MB. Mengapa? Karena 999950/1000 bernilai 999.950 yang secara efektif dibulatkan menjadi 1000.0 saat menggunakan String.format di Java (dalam sebagian besar bahasa lain juga). Hench diperlukan beberapa pemeriksaan tambahan untuk menangani kasus-kasus seperti ini.

Untuk tantangan ini, kedua gaya, 1000.0 kB dan 1.0 MB diterima, meskipun gaya terakhir lebih disukai.

Kode semu / kode uji java:


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

Rolf ツ
sumber
1
Secara teknis, SI kilobyte harus digunakan kB(perhatikan huruf kecil k)
SuperJedi224
Poin bagus, tetap!
Rolf ツ
1
Saya tidak ingin membatasi terlalu banyak, jadi saya akan mengatakan spasi mungkin tidak konsisten. Tetapi dengan aturan ini: Perbedaan karakter spasi dan tab untuk input valid yang berbeda mungkin tidak melebihi 10. (Agar semuanya sedikit "dapat dibaca manusia")
Rolf ツ
2
Untuk apa output yang diharapkan 999999dan 1000000? 160581pameran pembulatan, sehingga harus itu 1000.0kBdan 1.0MB?
Sp3000
3
@ Sp3000 Itu pertanyaan yang bagus, solusi terbaik adalah 999999 untuk menampilkan 1,0 MB. Tetapi untuk tantangan ini saya akan mengatakan 1000.0 KB dan pembulatan serupa juga baik-baik saja.
Rolf ツ

Jawaban:

10

TI-BASIC, 44

Akan menjadi alat yang tepat untuk pekerjaan itu jika TI-BASIC memiliki setengah manipulasi string yang layak (saya harus resor untuk menimpa eksponen nomor, ditampilkan dalam notasi teknik, dengan unit). Seperti itu putaran dan keluaran dengan benar, tetapi bahkan tidak dekat dengan entri pemenang. Mungkin bahasa kalkulator lain bisa memenangkan yang ini?

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

Masukan dalam formulir [number]:[program name]di homescreen.

Kasus uji yang diberikan:

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
lirtosiast
sumber
Saya sama sekali tidak tahu bahwa TI-BASIC sangat serbaguna haha
Beta Decay
1
TI-BASIC tidak serba guna, tetapi sering ada solusi yang aneh untuk beberapa kekurangannya.
lirtosiast
6

CJam, 35 27 byte

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

Terima kasih Dennis untuk menghapus 8 byte.

Ini tidak mencetak .0dalam juru bahasa online . Tapi seperti yang ditunjukkan Dennis , ini berfungsi dengan baik dalam interpreter Java.

Penjelasan

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.
jimmy23013
sumber
ri{_e-3XmO_i}g;o]," kMG"='B(27 byte)
Dennis
@Dennis Terima kasih atas 1mO. Tetapi kode ini tidak berfungsi untuk 1149999...
jimmy23013
ri{_e-3_i}g;1mOo]," kMG"='BSebaiknya.
Dennis
Gosok itu, yang memiliki bug lain.
Dennis
999999menjadi 1000kB. Membaca pertanyaan itu lagi, saya tidak yakin apakah 1000kBbenar-benar salah.
Dennis
5

Pyth, 29 27 byte

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

Demonstrasi. Uji Harness.

Penjelasan:

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'.
isaacg
sumber
3

CJam, 28

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

Cobalah online

Catatan: ini tidak menunjukkan ".0" dengan penerjemah online, tetapi melakukannya dengan pejabat penerjemah java .

Penjelasan:

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'
aditsu
sumber
Untuk apa backtick itu?
Dennis
@Dennis menunjukkan .0 dalam juru bahasa online
aditsu
Ini berfungsi dengan baik di interpreter Java tanpa backtick, jadi saya tidak berpikir Anda membutuhkannya.
Dennis
3

Python 2 - 76 byte

Menggunakan Sistem Unit Internasional, hanya karena lebih mudah dilakukan di kepala Anda;)

n=input();m=0;f=1e3
while n>=f:n/=f;m+=2
print"%.1f%s"%(n,'B kBMBGB'[m:m+2])
Peluruhan Beta
sumber
tampaknya tidak ok untuk saya, tidak menghormati pemformatan yang diminta, sebagai contoh jika saya mengirimkan "2147483647" Saya memperoleh "2.000000GB" - Pertanyaannya meminta satu desimal, dan mungkin spasi.
pelaku diet
1
Juga, ini adalah 79 byte menurut ini . Ini adalah 75 byte. Saya tidak percaya itu ditentukan bahwa perlu ada ruang antara angka dan unit.
Kade
Anda dapat menyimpan satu byte denganf=1e3
mbomb007
@ mbomb007 Sebenarnya itu disimpan 2 byte karena 1e3 adalah float
Beta Decay
Saya tahu itu pelampung. Saya kira saya tidak bisa menghitung ...
mbomb007
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}

pemakaian

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:\>
mengoceh
sumber
2

Haskell, 119

Sayangnya saya tidak dapat menemukan cara yang lebih pendek di Haskell untuk memastikan 1 desimal di mengapung, tapi saya memposting untuk anak cucu.

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

Pemakaian:

> m 160581
"160.6kB"

Versi yang tidak terlalu golf:

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)
Craig Roy
sumber
2

Java, 106 byte

Ini adalah metode yang mengambil angka dan mengembalikan string.

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";}
SuperJedi224
sumber
Anda diizinkan memprogram fungsi yang mengembalikan string alih-alih program yang lengkap, ini dapat menghemat beberapa byte;)
Rolf ツ
Tiga hal: Jika Anda mengonversi a menjadi dobel (saya tidak tahu apakah itu perlu), Anda dapat menggunakannya 1e3untuk 1000; Anda dapat mengonversinya while()menjadi a for()dan menggunakan titik koma gratis; dan saya tidak tahu apakah ini berhasil karena tampaknya menampilkan semua angka desimal, bukan hanya satu yang melewati tempat desimal.
lirtosiast
@ThomasKwa: Terakhir saya periksa, pertanyaannya tampaknya tidak secara eksplisit menentukan itu. Tapi saya rasa itu sekarang.
SuperJedi224
1

Python 2, 127 byte

Menggunakan ISU. Cuplikan menyatakan fungsi 'C' yang mengambil nomor untuk dikonversi sebagai argumen.

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'

Beberapa kode uji:

    print 'Input\tOutput'
for v in [0,999,1000,1023,1023,1601,160581,4066888,634000000,2147483647]:
 print v,C(v)
pelaku diet
sumber
Anda dapat menggunakan 1e3sebagai gantinya1000.0
mbomb007
1

JavaScript ( ES6 ), 71

Menggunakan unit SI - Fungsi mengembalikan string yang diminta.

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

Yang lebih pendek ini mengikuti aturan, terutama 3 dan 4

  • Output harus selalu dalam unit terbesar yang mungkin di mana jumlah yang dihasilkan masih lebih tinggi atau sama dengan satu maka 995 => 1.0kB
  • Output harus selalu memiliki satu angka desimal, tetapi Anda dapat memilih untuk mencetak angka integer ketika output yang dihasilkan dalam byte (B) Saya memilih tidak, jadi 10 => 10.0 B

Sayangnya, dengan cara ini, hasilnya tidak cocok dengan contoh.

Untuk mencocokkan contoh, di sini adalah yang lebih panjang, casing khusus untuk jumlah kecil (82 byte)

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

Jalankan cuplikan untuk menguji (menjadi EcmaScript 6, hanya Firefox)

edc65
sumber
1

Python, 61 byte

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

Sebut seperti f(999). Perhatikan bahwa itu 1e3adalah float, jadi ini berfungsi baik dengan Python 2 dan Python 3.

Sp3000
sumber
1

PHP4.1, 63 62 byte

Bukan golf terbaik, tapi tentu saja cukup pendek.

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

Untuk menggunakannya, akses melalui POST / GET atau tetapkan nilai dalam SESI, pada tombol B.

Biarkan kunci Itidak disetel!

Ismael Miguel
sumber
1

SpecBAS - 100 byte

Menggunakan konvensi ISU.

Saya menyadari bahwa memiliki set variabel ke 1e3 (yang membutuhkan pernyataan LET untuk menetapkannya), dan kemudian menggunakan variabel itu dalam bekerja, benar-benar menggunakan lebih banyak karakter daripada hanya hardcoding 1e3 di mana itu diperlukan.

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"
Brian
sumber
1

Ruby, 128 byte

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}

Saya melakukannya dengan cara yang lama, ini sangat buruk.

Keluaran

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"

Edit

Menambahkan TB untuk 39 byte tambahan

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}

Keluaran:

c[1000000000000] # => "1.0TB"
Sheerforce
sumber
1

Sed -r , 218 + 1

Saya menggunakan unit SI; Saya pikir bahwa memilih unit biner akan menjadi kebijakan yang berani . ;-)

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

Dipformat ulang:

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

Keluaran

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

Variasi

Aturan tampaknya menyiratkan round-to-terdekat, tetapi untuk tampilan manusia, saya percaya pembulatan ke bawah adalah alternatif yang dapat diterima, dan menghemat 123 byte (lebih baik dari 50%):

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

Ekstensi alami ke unit yang lebih besar (masih dibulatkan, 130 + 1 byte):

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/

Output variasi:

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
Toby Speight
sumber
Kerja bagus! Saya suka Anda memikirkan semua opsi berbeda!
Rolf ツ
1

C, 77 75

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

Ini menggunakan unit SI dan mengambil opsi 1000.0kB untuk pembulatan.

Kode yang diperluas:

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

Keluaran

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

Varian

Untuk mendapatkan unit biner, ubah 1000menjadi 1024, dan tambahkan ike string format jika ada pengganda. Untuk menghindari 4-digit pembulatan, membandingkan >=.95bukan >=1. Untuk menerima unit yang lebih besar, perpanjang ustring. Menggabungkan semua opsi ini, kita dapatkan:

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

Output varian

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

Program uji

Lewati sejumlah input sebagai argumen baris perintah:

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

int main(int argc, char **argv)
{
    while (*++argv) {
        printf("%s => ", *argv);
        f(strtod(*argv, 0));
        puts("");
    }
    return 0;
}
Toby Speight
sumber
Bagus;) Eksekusi dengan baik!
Rolf ツ
0

Ruby, 91 byte

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

Saya mungkin bisa melakukan sedikit lebih baik jika saya berusaha lebih keras tetapi inilah yang saya dapatkan sejauh ini.

David Bailey
sumber
Gunakan 1024.sebagai ganti 1024.0.
mbomb007
0

Javascript ES5, 69 byte

Ini menggunakan cara berbeda untuk mencapai tujuan akhir yang dijawab @ edc65 .
Sebenarnya, ini cukup dekat dengan jawaban PHP saya .

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

Cukup jalankan snippet stack atau rekatkan ini di konsol Anda.

Ismael Miguel
sumber
0

Ruby, 90 byte

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}
csabahenk
sumber