Formatta il numero dato di byte in un formato leggibile


16

Sfida e origine

Su Stack Overflow una domanda popolare è: come convertire le dimensioni dei byte in formato leggibile dall'uomo in Java? La risposta più votata ha un metodo abbastanza carino per farlo, ma questo è codegolf e possiamo fare di meglio, no?

La tua sfida è quella di scrivere un metodo o un programma che copra il numero dato di byte nel formato corretto leggibile dall'uomo e stampi il risultato allo standard fuori dalla tua lingua. *

* Vedi le regole per maggiori chiarimenti!

Ingresso

L'input sarà sempre un numero positivo di byte con un massimo di (2 ^ 31) -1.

Produzione

Puoi scegliere se preferisci il Sistema internazionale di unità o la notazione binaria come output (la notazione SI probabilmente ti salva alcuni byte).

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

Nota: unità più alte di GB o GiB non sono possibili a causa del campo di ingresso limitato.

Esempio di output

Sistema internazionale di unità:

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

Binario:

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

Regole

  • Le funzioni integrate per la formattazione dei byte non sono consentite!
  • L'output dovrebbe essere sempre nello stesso standard di notazione, non è possibile combinare SI o binario;
  • L'output dovrebbe essere sempre nell'unità più grande possibile dove il numero risultante è ancora maggiore o uguale a uno;
  • L'output deve sempre avere un numero decimale, ma è possibile scegliere di stampare un numero intero quando l'output risultante è in byte (B);
  • Puoi scegliere se aggiungere uno spazio, una scheda o nulla tra il numero e l'unità;
  • L'ingresso viene ricevuto tramite STDIN o parametri di funzione;
  • L'output viene stampato sulla console o restituito come stringa (o contenitore di caratteri simili);
  • Questo è il codice golf, quindi vince la risposta più breve. Divertiti!

Modifica: ancora più chiarimenti

Alcuni numeri hanno comportamenti di arrotondamento interessanti come il numero 999950. La maggior parte delle implementazioni di codice restituirebbe 1000,0 kB anziché 1,0 MB. Perché? Perché 999950/1000 restituisce 999.950, che viene effettivamente arrotondato a 1000.0 quando si utilizza String.format in Java (anche nella maggior parte delle altre lingue). Hench alcuni controlli extra sono necessari per gestire casi come questo.

Per questa sfida sono accettati entrambi gli stili, 1000,0 kB e 1,0 MB, sebbene sia preferito l'ultimo stile.

Pseudo codice / codice test 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));
}


1
Tecnicamente, i kilobyte SI dovrebbero usare kB(notare il k minuscolo)
SuperJedi224

Buon punto, risolto!
Rolf ツ

1
Non voglio limitarmi a molto, quindi direi che la spaziatura potrebbe essere incoerente. Ma con questa regola: la differenza di caratteri di spazio e tabulazione per diversi input validi non può superare 10. (Per mantenere tutto un po '"leggibile dall'uomo")
Rolf ツ

2
Qual è l'output previsto per 999999e 1000000? 160581mostra arrotondamenti, quindi dovrebbe essere 1000.0kBe 1.0MB?
Sp3000,

3
@ Sp3000 Questa è una buona domanda, la soluzione migliore sarebbe che 999999 visualizzasse 1,0 MB. Ma per questa sfida direi che 1000,0 KB e simili casi di arrotondamento vanno bene.
Rolf ツ

Risposte:


10

TI-BASIC, 44

Sarebbe lo strumento giusto per il lavoro se TI-BASIC avesse una manipolazione della stringa a metà decente (dovevo ricorrere a sovrascrivere l'esponente del numero, visualizzato in notazione ingegneristica, con l'unità). Come viene arrotondato e prodotto correttamente, ma non è nemmeno vicino alle voci vincenti. Forse un linguaggio di calcolatrice diverso potrebbe vincere questo?

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

Inserisci nel modulo [number]:[program name]nella schermata iniziale.

Dati casi di test:

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

Non avevo assolutamente idea che TI-BASIC fosse così versatile haha
Beta Decay il

1
TI-BASIC non è versatile, ma ci sono spesso strane soluzioni per alcune delle sue carenze.
lirtosiast,

6

CJam, 35 27 byte

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

Grazie Dennis per aver rimosso 8 byte.

Questo non viene stampato .0nell'interprete online . Ma come ha sottolineato Dennis , funziona benissimo nell'interprete Java.

Spiegazione

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 byte)
Dennis,

@Dennis Grazie per il 1mO. Ma questo codice non funziona per 1149999...
jimmy23013

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

Grattalo, questo ha altri bug.
Dennis,

999999diventa 1000kB. Rileggendo la domanda, non sono sicuro che 1000kBsarebbe effettivamente sbagliato.
Dennis,

5

Pyth, 29 27 byte

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

Dimostrazione. Collaudare l'imbragatura.

Spiegazione:

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

Provalo online

Nota: non mostra ".0" con l'interprete online, ma lo fa con l' interprete java ufficiale .

Spiegazione:

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'

A cosa serve il backtick?
Dennis,

@Dennis mostra .0 nell'interprete online
aditsu,

Funziona bene nell'interprete Java senza il backtick, quindi non credo che ne abbia bisogno.
Dennis,

3

Python 2 - 76 byte

Utilizza il sistema di unità internazionale, semplicemente perché è più facile da fare nella tua testa;)

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

non mi sembra giusto, non rispetta la formattazione richiesta, ad esempio se invio "2147483647" ottengo "2.000000GB" - La domanda richiede un decimale e forse uno spazio.
Dieter,

1
Inoltre, si tratta di 79 byte secondo questo . Questo è di 75 byte. Non credo che sia stato specificato che ci deve essere uno spazio tra il numero e l'unità.
Kade,

puoi salvare un byte conf=1e3
mbomb007 il

@ mbomb007 In realtà ha salvato 2 byte perché 1e3 è un float
Decadimento beta

Sapevo che era un galleggiante. Immagino di non poter contare ...
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}

uso

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

Purtroppo non riesco a trovare un modo più breve in Haskell per garantire 1 decimale in float, ma sto postando per i posteri.

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

Uso:

> m 160581
"160.6kB"

Versione moderatamente meno giocata a 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)

2

Java, 106 byte

Questo è un metodo che accetta un numero e restituisce una stringa.

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

Hai il permesso di programmare una funzione che restituisce una stringa invece di un programma completo, può farti risparmiare qualche byte;)
Rolf ツ

Tre cose: se stai convertendo a in doppio comunque (non so se sia necessario), puoi usare 1e3per 1000; puoi convertirlo while()in a for()e usare i punti e virgola gratuiti; e non so se funziona perché sembra mostrare tutte le cifre decimali, non solo una cifra decimale.
lirtosiast,

@ThomasKwa: l'ultima volta che ho controllato, la domanda non sembrava specificarlo esplicitamente. Ma suppongo che lo faccia ora.
SuperJedi224,

1

Python 2, 127 byte

Utilizzando l'ISU. Lo snippet dichiara una funzione 'C' che accetta il numero da convertire come argomento.

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'

Alcuni codici di prova:

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

Puoi usare 1e3invece di1000.0
mbomb007 il

1

JavaScript ( ES6 ), 71

Uso delle unità SI - Una funzione che restituisce la stringa richiesta.

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

Questo più breve segue le regole, in particolare 3 e 4

  • L'output dovrebbe essere sempre nell'unità più grande possibile dove il numero risultante è ancora maggiore o uguale a uno quindi 995 => 1,0 kB
  • L'output deve sempre avere un numero decimale, ma è possibile scegliere di stampare un numero intero quando l'output risultante è in byte (B), io scelgo di no, quindi 10 => 10,0 B

Purtroppo, in questo modo, i risultati non corrispondono agli esempi.

Per abbinare gli esempi, eccone uno più lungo, speciale per numeri piccoli (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)

Esegui lo snippet per testare (essendo EcmaScript 6, solo Firefox)


1

Python, 61 byte

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

Chiama come f(999). Nota che 1e3è un float, quindi funziona sia con Python 2 che con Python 3.


1

PHP4.1, 63 62 byte

Non è il miglior golf, ma sicuramente è piuttosto breve.

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

Per usarlo, accedere tramite POST / GET o impostare un valore nella SESSIONE, sulla chiave B.

Lascia la chiave Idisinserita!


1

SpecBAS - 100 byte

Utilizzando la convenzione ISU.

Mi sono reso conto che avere una variabile impostata su 1e3 (che ha bisogno di un'istruzione LET per assegnarla), e quindi usando quella variabile nell'allenamento, ha effettivamente utilizzato più caratteri rispetto alla semplice codifica dell'1e3 dove era necessario.

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

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

L'ho fatto a lungo, questo è piuttosto male.

Produzione

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"

modificare

TB aggiunta per ulteriori 39 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&&i<1e12;p (i/1e12).to_s+'TB'if i>=1e12}

Produzione:

c[1000000000000] # => "1.0TB"

1

Sed -r, 218 + 1

Sto usando unità SI; Penso che la scelta di unità binarie sarebbe una politica coraggiosa . ;-)

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

riformattato:

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

Produzione

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

variazioni

Le regole sembrano implicare il arrotondamento al più vicino, ma per la visualizzazione umana, credo che arrotondare per difetto sia un'alternativa accettabile e risparmia 123 byte (meglio del 50%):

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

L'estensione naturale alle unità più grandi (ancora arrotondando per difetto, 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/

Uscita di variazione:

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

Ottimo lavoro! Mi piace che tu abbia pensato a tutte le diverse opzioni!
Rolf ツ

1

C, 77 75

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

Questo utilizza unità SI e accetta l'opzione 1000.0kB per l'arrotondamento.

Codice espanso:

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

Produzione

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

varianti

Per ottenere unità binarie, cambia 1000in 1024e aggiungi ialla stringa di formato se c'è un moltiplicatore. Per evitare l'arrotondamento di 4 cifre, confrontare >=.95invece di >=1. Per accettare unità più grandi, estendi la ustringa. Combinando tutte queste opzioni, otteniamo:

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

Uscita variante

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

Programma di test

Passa un numero qualsiasi di input come argomenti della riga di comando:

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

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

Bello;) Ben eseguito!
Rolf ツ

0

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

Probabilmente potrei fare un po 'meglio se ci provassi di più, ma ecco cosa ho ottenuto finora.


Usa 1024.invece di 1024.0.
mbomb007,

0

Javascript ES5, 69 byte

Questo utilizza un modo diverso per raggiungere l'obiettivo finale che la risposta di @ edc65 .
In realtà, questo è abbastanza vicino alla mia risposta PHP .

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

Basta eseguire lo snippet dello stack o incollarlo sulla console.


0

Rubino, 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}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.