Сделайте это объяснение кода снова довольно

17

Вступление

Большинство разработчиков кода добавляют здесь объяснения к своим материалам, чтобы было легче понять, что происходит. Обычно строки кода идут слева, а соответствующее объяснение справа с каким-то разделителем. Чтобы это выглядело красиво, все разделители находятся в одном столбце. Кроме того, длинный текст объяснения обычно переносится на следующую строку, поэтому читателям не нужно прокручивать текст по горизонтали, чтобы прочитать все.

Однако, когда вы хотите отредактировать это объяснение, потому что вы сделали несколько сумасшедших гольфов, вы часто заканчиваете тем, что тратите время, чтобы сделать это объяснение довольно симпатичным. Поскольку это очень повторяющаяся задача, вы хотите написать программу для этого.

Соревнование

Учитывая несколько строк кода с объяснением и разделителем, выведите красиво отформатированный код с объяснением.

пример

вход

shM-crz1dc4. "ANDBYOROF # z = вход

     rz1 # преобразовать ввод в верхний регистр
    cd # разделить ввод по пробелам
         c4. "ANDBYOROF # создать список слов из упакованной строки, которые должны игнорироваться
   - # отфильтровать эти слова
 hM # взять только первую букву всех слов
s # объединить их в одну строку

Выход

shM-crz1dc4. "ANDBYOROF # z = вход

     rz1 # преобразовать ввод в верхний регистр
    cd # разделить ввод по пробелам
         c4. "ANDBYOROF # создать список слов из упакованной строки, которая должна быть
                           # игнорируется
   - # отфильтровать эти слова
 hM # взять только первую букву всех слов
s # объединить их в одну строку

Один файл cookie для первого, кто может узнать, что делает этот код.

Алгоритм форматирования

  • Найдите самую длинную строку кода (исключая пояснения и пробелы между кодом и разделителем).
  • Добавьте 5 пробелов после этой строки кода и добавьте соответствующий разделитель с пояснениями. Это теперь опорная линия.
  • Настройте все остальные строки в этой опорной линии, так что все сепаратора обеспечивают в одном столбце.
  • Оберните все строки длиной более 93 символов в новую строку следующим образом:
    • Найдите последнее слово, конец которого находится в столбце 93 или ниже.
    • Возьмите все слова после этого и перенесите их на новую строку с ведущим разделителем и правильным интервалом. Пробел между этими двумя словами должен быть удален, поэтому первая строка заканчивается символом слова, а вторая строка начинается с одного после разделителя.
    • Если полученная строка все еще длиннее 93 символов, делайте то же самое снова, пока каждая строка не станет ниже 94 символов.

Примечания

  • Слово состоит из непробельных символов. Слова разделяются одним пробелом.
  • Перенос слов всегда возможен. Это означает, что ни одно слово не может быть таким длинным, чтобы сделать обертку невозможной.
  • Входные данные будут содержать только печатный ASCII и не будут содержать пробелы в конце
  • Разделитель будет отображаться только один раз в строке.
  • Хотя объяснение может иметь неограниченную длину, разделитель и код могут иметь только суммарную максимальную длину 93 - 5 = 87символов. 5 символов - это пробелы между кодом и разделителем. Код и разделитель всегда будут длиной не менее одного символа.
  • Входные данные могут содержать пустые строки. Они никогда не будут содержать никаких символов (кроме новой строки, если вы берете ввод в качестве многострочной строки). Эти пустые строки также должны присутствовать в выводе.
  • Каждая строка будет иметь некоторый код, разделитель и объяснение. Исключение составляют пустые строки.
  • Вы можете принять ввод в любом разумном формате, если он не был предварительно обработан. Укажите в своем ответе, какой из них вы используете.
  • Вывод может быть многострочной строкой или списком строк.

правила

Контрольные примеры

Формат ввода здесь представляет собой список строк, представляющих строки и одну строку для разделителя. Оба разделены запятой. Вывод представляет собой список строк.

['shM-crz1dc4. "ANDBYOROF # z = input', '', 'rz1 # преобразовать ввод в верхний регистр', 'cd # разделить ввод пробелами', 'c4." ANDBYOROF # создать список слов из упакованного строка, которая должна игнорироваться ',' - # отфильтровать эти слова ',' hM # взять только первую букву всех слов ',' s # объединить их в одну строку '], "#" -> [' shM-crz1dc4 . "ANDBYOROF # z = input ',' ',' rz1 # преобразовать ввод в верхний регистр ',' cd # разбить ввод на пробелы ',' c4. 'ANDBYOROF # создать список слов из упакованной строки, которая должна быть' , '# игнорируется', '- # отфильтровать эти слова ',' hM # взять только первую букву всех слов ',' s # объединить их в одну строку ']
['codecodecode e # Объяснение', 'sdf dsf sdf e # A Очень, очень, очень, очень, очень, очень, очень, очень, очень долго, долго, долго, долго, долго, долго, долго, долго, долго, долго, и это становится все длиннее и длиннее.', '', 'some больше коде # и еще несколько объяснений '], "e #" -> [' codecodecode e # Объяснение ',' sdf dsf sdf e # A Очень, очень, очень, очень, очень, очень, очень, очень, очень долго, долго, долго, долго, долго »,« e # long. длинное длинное длинное длинное длинное объяснение, и оно становится все длиннее ',' e # и дольше ',' ',' еще немного кода e # и еще больше объяснений ']

Удачного кодирования!

Denker
источник
1
@Matt Все разделители всегда в столбце length of the longest code-line + 5. Это также относится к строкам, которые содержат только пояснения, потому что они были перенесены.
Денкер
Боже мой, я делаю это неправильно в течение последних 3 часов. Я пытался обернуть длинный код и оставить объяснения долго ..... Ну, начиная с начала. По крайней мере, теперь это стало проще. Благодарю. Вы сформулировали это хорошо .... Я просто глупый.
Мэтт
Перенос всех строк длиной более 93 символов. Означает ли это, что код, включая начальные пробелы, никогда не будет длиннее 87 символов?
Мэтт
@Matt Код и разделитель никогда не будут длиннее 87 символов, так как нам нужно 5 пробелов между кодом и разделителем и один символ для объяснения.
Денкер
1
Код Pyth находит аббревиатуру любой данной строки. Я бы знал, потому что это был ответ на мой вопрос.
Aplet123

Ответы:

3

Рубин, 245 237 220 216 212 209 205 байт

Анонимная функция. Довольно базовый подход (найдите максимальную длину, добавьте 5, затем выполните обработку в каждой строке с рекурсией, чтобы справиться с переносом), и может быть другой подход, который экономит больше байтов.

Ранее я удалил ответ, который не удовлетворял всем требованиям; Я не хотел, чтобы в качестве ответа использовался код с половинным ответом (он тоже получал отрицательные отзывы за то, что он был неполным), но теперь он должен делать все, о чем просит вопрос.

->x,d{l,S=0," "
s=->n{m,q=n.size,94-l-d.size
m>q ?(i=n.rindex(S,q)
n[0,i]+"
"+S*l+d+s[n[i+1,m]]):n}
x.map{|n|c,t=n.split d
c=(c||S).rstrip
l=[l,5+c.size].max
[c,t]}.map{|c,t|c+S*(l-c.size)+d+s[t]if t}*"
"}

Changelog:

  • Сохранение некоторых байтов за счет использования некоторых обещаний на входе, особенно обещания, что все непустые строки имеют символ-разделитель и объяснение.
  • Удалось немного поиграть в гольф, сохранив разделенные строки из первого mapвызова и выполнив некоторые ненужные stripфункции, основываясь на обещании, что слова в объяснении всегда имеют ровно один пробел между ними. Кроме того, " "теперь присваивается константа, так как я так часто ее использую.
  • Обе цепочки обоих mapвызовов объединены, используя мощь функций более высокого порядка, что означает, что первый вызов карты будет lправильно устанавливать переменную длины, даже если он вызывается после объявления вспомогательной функции s. -4 байта.
  • Злоупотребление многострочными строками для замены \nреальными символами новой строки, а также небольшая хитрость с использованием ifболее троичных операторов (при joinвызове массива со nilзначениями они становятся пустыми строками)
  • .joinпо-видимому, может быть заменен на *.
Значение чернил
источник
Я думаю, что это должно быть исправлено сейчас?
Value Ink
как это обернуть в 94?
Ven
Хорошо, теперь, когда у меня было больше времени для работы с кодом, он правильно упакован.
Value Ink
«Хотя объяснение может иметь неограниченную длину, разделитель и код могут иметь только общую максимальную длину 93 - 5 = 87символов. 5 символов - это пробелы между кодом и разделителем. Код и разделитель всегда будут иметь длину не менее одного символа». Ваш раздел кода далеко за пределом, с 97 символами, поэтому программа имеет неопределенное поведение.
Value Ink
ах, хорошо заметили, имеет смысл!
Ven
9

LiveScript, 243 236 233 228 219 225 байт

f = (x,k,m+5)->l=(.length);x.=map(->it/"#k"=>..0-=/ +$/;m>?=5+l ..0);i=0;[..0&&..0+' '*(m- l ..0)+k+..1 for x]=>while i<(l ..),++i=>j=(s=..[i])lastIndexOf ' ' 93;(..splice i+1 0 ' '*m+k+s[j to]*'';s.=substr 0 j) if 94<l s;..[i]=s

Как это работает: в основном, как код Java. Начните с псевдонима длины (LiveScript позволяет создать функцию из операторов с помощью круглых скобок). .=это a = a.b- что мы используем здесь, чтобы отобразить.

=> blabla ..является каскадной конструкцией Smalltalk-ih: левая сторона =>доступна как ..для остальной части блока; и будет возвращен. Здесь это элемент разбит на k. Примечание: я использую интерполяцию строк, потому что /означает только «разделить» с литеральной строкой.

LS позволяет нам использовать и a-=/regexp/в этой лямбде (также работает со строковыми литералами): это просто сахар для .replaceвызова.

Наконец, >?=это комбинаторный >?оператор -assin, который возвращает больший из двух операндов.

У LS есть Python / Haskell-стиль для понимания, в котором нет ничего фантастического, кроме «string * times», чтобы повторять пространство достаточно долго.

Это для понимания служит темой (см. Блок о каскадах anove).

Затем мы зациклились на каждом элементе массива (тот, который мы только что построили с пониманием), и, если какая-либо строка больше 93 символов, мы находим последний индекс, разделяем его и вставляем разделенную строку сразу после текущей итерации ( ... чтобы следующая итерация снова разбилась, если строка слишком большая).

Только последняя вещь фантазии a[j to]является диапазон (от J до конца), но так как он использует методы массива мы должны объединить его обратно в строку, которая нам использовать перегруженный *: *''.

пример

s = """this is kod # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
d # y

efgh # z"""

f = (x,k,m=5)->l=(.length);x.=map(->it/"#k"=>..0-=/ +$/;m>?=5+l ..0);i=0;[..0&&..0+' '*(m- l ..0)+k+..1 for x]=>while i<(l ..),++i=>j=(s=..[i])lastIndexOf ' ' 93;(..splice i+1 0 ' '*m+k+s[j to]*'';s.=substr 0 j) if 94<l s;..[i]=s

console.log (f s / '\n', '#') * \\n

выход:

this is kod     # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
                # tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
                # veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
                # commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
                # velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
                # cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
                # est laborum.
d               # y

efgh            # z
Вен
источник
1
для тех, кто отрицал: ответ является фиксированным.
Ven
2
Когда объяснение переполняется, вам нужны новые строки, чтобы выровнять их символы-разделители с остальными, IIRC.
Чернила стоимости
@KevinLau хорошо заметили, исправили!
Ven
Можете ли вы обновить вывод примера?
Стоимость чернил
@KevinLau сделано.
Ven
6

Java, 347 + 19 = 366 байт

требует

import java.util.*;

Таким образом, +19 байт.

(c,s)->{int p=0,i=0,t;String l;for(;i<c.size();i++){l=c.get(i);l=l.replaceAll(" *"+s,s);p=Math.max(l.indexOf(s),p);c.set(i,l);}p+=5;for(i=0;i<c.size();i++){l=c.get(i);t=l.indexOf(s);while(t>-1&t<p)l=l.substring(0,t)+" "+l.substring(t++);t=93;if(l.length()>t){while(l.charAt(t)!=' ')t--;c.add(i+1,s+l.substring(t));l=l.substring(0,t);}c.set(i,l);}}

Берет в формате f.accept(List<String> code, String seperator). Форматы на месте. Версия, которая создает и возвращает новую List<String>, будет тривиальна для реализации, но будет стоить несколько байтов.

Отступ + пример использования:

static BiConsumer<List<String>, String> prettify = (code, seperator) -> {
    int space = 0, i=0, t;
    String line;
    for (; i<code.size(); i++) { // for each line
        line = code.get(i); // get line
        line = line.replaceAll(" *" + seperator, seperator); // strip space before seperator
        space = Math.max(line.indexOf(seperator), space); // save biggest space until seperator
        code.set(i, line); // save line
    }
    space += 5;
    for (i=0; i<code.size(); i++) { // for each line
        line = code.get(i); // get line
        t = line.indexOf(seperator); // get index of seperator
        while (t>-1&t<space) // while the seperator exists and is further left than desired
            line = line.substring(0,t) + " " + line.substring(t++); // move it right by adding a space before it
        t = 93; // get desired line length
        if (line.length()>t) { // if the line is longer than that
            while (line.charAt(t)!=' ') t--; // scan backwards for a space
            code.add(i+1, seperator + line.substring(t)); // add a line after this one with seperator and the rest of the line
                                                          // the next pass will space it correctly
            line = line.substring(0,t); // cut off this line at that point
        }
        code.set(i, line); // save edited line back to List
    }
};

public static void main(String[] args) {
    List<String> code = new ArrayList<>();
    code.add("shM-crz1dc4.\"ANDBYOROF  # z = input");
    code.add("");
    code.add("     rz1      # convert input to uppercase");
    code.add("    c   d        # split input on spaces");
    code.add("         c4.\"ANDBYOROF        # create a list of the words from a packed string which shall be ignored");
    code.add("   -          # filter those words out");
    code.add(" hM                # only take the first letter of all words");
    code.add("s                   # join them into one string");
    prettify.accept(code, "#");
    code.stream().forEach(System.out::println);
}

... я, наверное, должен запустить это через себя: P

CAD97
источник
Если кто-то может понять, почему replace(" *"+s)не работает, но replaceAll(" *"+s)я хотел бы услышать это - я не могу понять это.
CAD97
<badguess> replaceиспользует строки, но replaceAllиспользует регулярные выражения. </ badguess>
CalculatorFeline
@CatsAreFluffy хорошо, ты прав ! Не знаю, как я этого не осознавал: P
CAD97
Вы не можете удалить перевод строки?
CalculatorFeline
Ну, перевод строки может быть удален из-за обязательных значений: s (что должно быть .s, но неважно)
CalculatorFeline
2

PowerShell, 224 217 235 байт

param($d,$s)$d=$d-split"`r`n";$p="\s+\$([char[]]$s-join"\")\s";$m=($d|%{($_-split$p)[0].Length}|sort)[-1];$d|%{$l,$c=$_-split$p;$c=if($c){"$s "+(("$c "-split"(.{1,$(87-$m)})\s"|?{$_})-join"`n$(" "*($m+5))$s ")}$l.PadRight($m+5," ")+$c}

Обновлена ​​логика для определения максимальной длины строки кода. Обновлен, чтобы разрешить несколько разделителей, которые включают метасимволы регулярных выражений.


Маленькое объяснение

Это берет целую строку с разделителем новой строки для ввода.

param($d,$s)
# $d is a newline delimited string. $s is the separator.
# Take the string and turn it into a string array. Stored as $d
$d=$d-split"`r`n"
# Save a regex pattern as it is used more than once
$p="\s+\$([char[]]$s-join"\")\s"
# Get the longest string of code's length
$m=($d|%{($_-split$p)[0].Length}|sort)[-1]
# Split each line again into code and comment. Write out each line with formatted explanations based on separator column position $m
$d|%{
# Split the line
$l,$c=$_-split$p
# Build the comment string assuming there is one.
$c=if($c){"$s "+(("$c "-split"(.{1,$(87-$m)})\s"|?{$_})-join"`n$(" "*($m+5))$s ")}
# Pad the right amount of space on the code and add the comment string.
$l.PadRight($m+5," ")+$c
}

Пример вывода с использованием Lorem Ipsum

shM-crz1dc4."ANDBYOROF     # z = input

     rz1                   # convert input to uppercase
    c   d                  # split input on spaces
         c4."ANDBYOROF     # But I must explain to you how all this mistaken idea of
                           # denouncing pleasure and praising pain was born and I will give
                           # you a complete account of the system, and expound the actual
                           # teachings of the great explorer
   -                       # filter those words out
 hM                        # only take the first letter of all words
s                          # join them into one string
Matt
источник
@nimi Надеюсь, что теперь обновления сделают лучшее решение.
Мат
@nimi Что-то еще вы заметили неправильно? У меня, видимо, проблемы с чтением за последние пару дней.
Мэтт
Нет. Теперь есть +1.
nimi
1

MATLAB, 270 265 262 байта

function d=f(I,s);S=@sprintf;R=@regexprep;m=regexp(I,['\s*\',s]);L=max([m{:}])+4;a=@(x)S('%-*s%s',L,x,s);b=@(x)R(R(x,S('(.{1,%d}(\\s+|$))',93-L),S('$1\n%*s ',L+1,s)),['\n\s*\',s,' $'],'');c=R(I,['(.*?)\s*\',s,'\s*(.*$)'],'${a($1)} ${b($2)}');d=S('%s\n',c{:});end

Программа принимает входные данные Iв виде массива ячеек строк, где каждый элемент массива ячеек является отдельной строкой ввода. Он также принимает второй вход, который указывает, что символ комментария (то есть #). Функция возвращает многострочную строку, которая правильно отформатирована.

Краткое объяснение

function d = f(I,s)
    %// Setup some shortcuts for commonly-used functions
    S = @sprintf;
    R = @regexprep;

    %// Find the location of the space AFTER each code block but before a comment
    m = regexp(I, ['\s*\',s]);

    %// Compute the maximum column location of the code and add 4 (5 - 1)
    L = max([m{:}]) + 4;

    %// This is a callback for when we detect code
    %// It left justifies and pads the string to L width
    a = @(x)S('%-*s%s', L, x, s);

    %// This is a callback for when we detect a comment.
    b = @(x)R(...
            R(x, ...
                S('(.{1,%d}(\\s|$))', 93 - L), ... Regex for wrapping text to desired width
                S('$1\n%*s ', L+1, s)), ... Append a newline and padding for next line 
            ['\n\s*\',s,' $'], ''); ... Remove the trailing newline (to be improved)

    %// Perform replacement of everything.
    c = R(I, ...
            ['(.*?)\s*\',s,'\s*(.*$)'], ... Match "code comment_char comment"
            '${a($1)} ${b($2)}');   ... Replace using the output of the callbacks

    %// Concatenate all of the strings together with a newline in between
    d=S('%s\n',c{:});
end

Пример ввода

I = {
    'shM-crz1dc4."ANDBYOROF  # z = input'
    ''
    '     rz1      # convert input to uppercase'
    '    c   d        # split input on spaces'
    '         c4."ANDBYOROF        # create a list of the words from a packed string which shall be ignored'
    '   -          # filter those words out'
    ' hM                # only take the first letter of all words'
    's                   # join them into one string'
};

disp(f(I,'#'));

Пример вывода

shM-crz1dc4."ANDBYOROF     # z = input

     rz1                   # convert input to uppercase
    c   d                  # split input on spaces
         c4."ANDBYOROF     # create a list of the words from a packed string which shall be
                           # ignored
   -                       # filter those words out
 hM                        # only take the first letter of all words
s                          # join them into one string
Suever
источник