Отформатируйте заданное количество байтов в удобочитаемый формат


16

Вызов и происхождение

На Stack Overflow популярный вопрос: как преобразовать размер байта в читабельный формат в Java? Ответ с наибольшим количеством голосов имеет довольно хороший способ сделать это, но это Codegolf, и мы можем сделать лучше, не так ли?

Ваша задача состоит в том, чтобы написать метод или программу, которая покрывает заданное количество байтов в правильном читабельном формате и выводит результат на стандартный язык из вашего языка. *

* Ознакомьтесь с правилами для уточнения!

вход

Ввод всегда будет положительным числом байтов с максимумом (2 ^ 31) -1.

Выход

Вы можете выбрать, предпочитаете ли вы Международную систему единиц или двоичную нотацию в качестве выходных данных (нотация SI, вероятно, экономит вам несколько байтов).

SI:      B, kB,  MB,  GB  
Binary:  B, KiB, MiB, 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

Binary:

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 или двоичный код;
  • Выходные данные всегда должны быть в максимально возможной единице, где результирующее число все еще больше или равно единице;
  • Выходные данные всегда должны иметь одно десятичное число, но вы можете распечатать целое число, если результирующий вывод представлен в байтах (B);
  • Вы можете выбрать, хотите ли вы добавить пробел, табуляцию или ничего между числом и единицей;
  • Ввод принимается через STDIN или параметры функции;
  • Вывод выводится на консоль или возвращается в виде строки (или аналогичного символьного контейнера);
  • Это код гольф, поэтому самый короткий ответ выигрывает. Веселиться!

Изменить: еще больше уточнений

Некоторые числа имеют интересное поведение округления, например, число 999950. Большинство реализаций кода возвращает 1000,0 кБ вместо 1,0 МБ. Почему? Потому что 999950/1000 оценивается до 999.950, который фактически округляется до 1000.0 при использовании String.format в Java (в большинстве других языков тоже). Хенч требует дополнительных проверок для обработки подобных случаев.

Для этой задачи принимаются оба стиля: 1000,0 кБ и 1,0 МБ, хотя последний стиль является предпочтительным.

Псевдокод / ​​тестовый код 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.0kBи 1.0MB?
Sp3000

3
@ Sp3000 Хороший вопрос, самое лучшее решение для 999999 - 1,0 МБ. Но для этой задачи я бы сказал, что 1000,0 КБ и подобные случаи округления тоже подойдут.
Рольф ツ

Ответы:


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 был настолько универсален, ха-ха
Beta Decay

1
TI-BASIC не универсален, но есть некоторые странные обходные пути для некоторых из его недостатков.
lirtosiast

6

CJam, 35 27 байтов

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

Спасибо Денису за удаление 8 байт.

Это не печатается .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 байт)
Деннис

@ Денис Спасибо за 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'

Для чего нужен обратный удар?
Деннис

@Dennis показывает .0 в онлайн-переводчике
aditsu

Он отлично работает в интерпретаторе 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
Кроме того, это 79 байтов в соответствии с этим . Это 75 байтов. Я не верю, что было указано, что между числом и единицей должен быть пробел.
Каде

Вы можете сохранить один байт сf=1e3
mbomb007

@ mbomb007 На самом деле он сэкономил 2 байта, потому что 1e3 является float
Beta Decay

Я знал, что это поплавок. Я думаю, я просто не могу сосчитать ...
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}

использование

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

Вам разрешено программировать функцию, возвращающую строку вместо полной программы, это может сэкономить вам несколько байтов;)
Рольф ツ

Три вещи: если вы все равно конвертируете в удвоение (я не знаю, нужно ли это), вы можете использовать 1e3для 1000; вы можете преобразовать это while()в a for()и использовать свободные точки с запятой; и я не знаю, работает ли это, потому что кажется, что он отображает все десятичные цифры, а не только одну после десятичной точки.
lirtosiast

@ThomasKwa: Последний раз, когда я проверял, вопрос явно не указывал это. Но я думаю, что теперь.
SuperJedi224

1

Python 2, 127 байт

Используя ИСУ. Фрагмент объявляет функцию '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

Использование единиц СИ - функция, возвращающая запрошенную строку.

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

Этот более короткий следует правилам, особенно 3 и 4

  • Выходные данные всегда должны быть в максимально возможной единице, где полученное число все еще больше или равно единице. чем 995 => 1,0 кБ
  • Выходные данные всегда должны иметь одно десятичное число, но вы можете распечатать целое число, если результирующий вывод находится в байтах (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 или установите значение в СЕССИИ на клавише 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 байтов

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

Я использую единицы СИ; Я думаю, что выбор бинарных единиц был бы смелой политикой . ;-)

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

С 77 75

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

Это использует единицы СИ и берет опцию 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;
}

Хороший один;) Хорошо выполнен!
Рольф ツ

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

Javascript ES5, 69 байт

Это использует другой способ достижения конечной цели, который отвечает @ edc65 .
На самом деле, это довольно близко к моему ответу 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}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.