指定されたバイト数を人間が読める形式にフォーマットします


16

挑戦と起源

スタックオーバーフローに関する一般的な質問は、Javaでバイトサイズを人間が読める形式に変換する方法です。最もよく投票された答えにはこれを行うための非常に良い方法がありますが、これはcodegolfであり、私たちはもっとうまくやることができますか?

あなたの課題は、与えられたバイト数を人間が読める正しい形式に変換し、その結果を言語から標準に出力するメソッドまたはプログラムを作成することです。*

*詳細については、ルールを参照してください!

入力

入力は常に最大(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以上です。
  • 出力には常に1つの10進数が含まれている必要がありますが、結果の出力がバイト(B)である場合は整数を印刷することもできます。
  • 数字と単位の間にスペース、タブを追加するか、何も追加しないかを選択できます。
  • 入力は、STDINまたは関数パラメーターを介して受信されます。
  • 出力はコンソールに出力されるか、文字列(または同様の文字コンテナー)として返されます。
  • これはコードゴルフであるため、最短の回答が勝ちます。楽しんで!

編集:さらに明確化

一部の数値には、999950のような興味深い丸め動作があります。ほとんどのコード実装は、1.0 MBではなく1000.0 kBを返します。どうして?999950/1000は999.950に評価されるため、JavaでString.formatを使用する場合(他のほとんどの言語でも)、事実上1000.0に丸められます。このようなケースを処理するには、いくつかの追加チェックが必要です。

この課題では、両方のスタイル、1000.0 kBと1.0 MBが受け入れられますが、最後のスタイルが優先されます。

擬似コード/ 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
技術的には、SIキロバイトで使用する必要がありますkB(小文字のkに注意してください)
SuperJedi224

良い点、修正済み!
ロルフツジュン

1
あまり制限したくないので、間隔に一貫性がない可能性があります。しかし、このルールでは:異なる有効な入力のスペースとタブ文字の差は10を超えてはなりません(それを少し「人間が読める」状態に保つため)
ロルフツジュン

2
999999およびに期待される出力は何1000000ですか?160581展示丸め、それがあるべき1000.0kB1.0MB
Sp3000

3
@ Sp3000これは良い質問です。最も良い解決策は、999999が1.0 MBを表示することです。しかし、この課題については、1000.0 KBと同様の丸めの場合も問題ないと思います。
ロルフツ

回答:


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は汎用性がありませんが、その欠点のいくつかについては奇妙な回避策がしばしばあります。
リルトシアスト

6

CJam、35 27バイト

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

8バイトを削除してくれたDennisに感謝します。

これはオンライン通訳.0では印刷されません。しかし、デニスが指摘したように、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をありがとう1mO。しかし、このコードは動作しません1149999...
jimmy23013

ri{_e-3_i}g;1mOo]," kMG"='Bする必要があります。
デニス

スクラッチ、それは他のバグがあります。
デニス

999999になり1000kBます。質問をもう一度読んで、1000kB実際に間違っているかどうかはわかりません。
デニス

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'

バックティックとは何ですか?
デニス

オンライン通訳で.0を表示する
@Dennis

Javaインタープリターではバックティックなしで正常に機能するため、必要ないと思います。
デニス

3

Python 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」を取得します-質問は小数点以下1桁、おそらくスペースを要求します。
ダイエット

1
また、これはによると79バイトで、このこれは75バイトです。数字と単位の間にスペースが必要であると特定されたとは思わない。
ケード

あなたが1つのバイトを保存することができますf=1e3
mbomb007

@ mbomb007 1e3は浮動小数点数であるため、実際には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

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

あなたはそれはあなたにいくつかのバイトを保存することが、完全なプログラムの代わりに文字列を返す関数をプログラムすることが許可されている;)
ロルフ・ツに

3つのこと:とにかくaをdoubleに変換する場合(必要かどうかはわかりません)、1e3for を使用できます1000。それwhile()をaに変換してfor()無料のセミコロンを使用できます。小数点以下1桁だけでなく、すべての小数点を表示しているように見えるため、これが機能するかどうかはわかりません。
リルトシアスト

@ThomasKwa:最後に確認したところ、質問はそれを明示的に指定していないようでした。しかし、今はそうなっていると思います。
SuperJedi224

1

Python 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

JavaScript(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です。
  • 出力には常に1つの10進数が含まれている必要がありますが、結果の出力がバイト単位である場合は整数を印刷することを選択できます(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

Python、61バイト

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

のように呼び出しf(999)ます。注1e3フロートので、両方のPython 2とPython 3と、この作品。


1

PHP4.1、 63 62バイト

最高のゴルフではありませんが、確かに非常に短いです。

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

それを使用するには、POST / GET経由でアクセスするか、キーのSESSIONに値を設定します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

セッド-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

よくやった!私はあなたがすべての異なるオプションについて考えたことを気に入っています!
ロルフツ

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

バリアント

バイナリ単位を取得するには、に変更10001024i乗数がある場合はフォーマット文字列に追加します。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;
}

素敵なもの;)よく実行されました!
ロルフツ

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

ルビー、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.