Зробіть це пояснення кодом ще раз гарним


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 = вхід', '', 'rz1 # перетворити вхід у великі регістри', 'cd # розділений вхід на пробіли', 'c4." ANDBYOROF # створити список слів із упакованого. рядок, який слід ігнорувати ',' - # відфільтрувати ці слова ',' hM # візьміть лише першу букву всіх слів ',' s # з'єднайте їх в одну рядок '], "#" -> [' shM-crz1dc4 . "ANDBYOROF # z = вхід", "", "rz1 # перетворити вхід у великі регістри", "cd # розділити введення на пробіли", "c4." ANDBYOROF # створити список слів із упакованого рядка, який повинен бути " , '# ігнорується', '- # відфільтруйте ці слова ',' hM # візьміть лише першу букву всіх слів ',' s # приєднайте їх до одного рядка ']
['codecodecode e # Пояснення', 'sdf dsf sdf e # A Дуже дуже-дуже-дуже-дуже-дуже-дуже-довгий-довгий-довгий-довгий-довгий довгий довге пояснення, і це стає все довше і довше', '', 'деякі більше codee # та ще декілька пояснень '], "e #" -> [' codecodecode e # Пояснення ',' sdf dsf sdf e # A Дуже дуже-дуже-дуже-дуже-дуже-дуже довго-довго-довго-довго ',' e # long довго довге довге довге пояснення, і воно триває все довше ',' e # і довше ',' ',' ще трохи коду e # та ще кілька пояснень ']

Щасливе кодування!


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

Журнал змін:

  • Збережено деякі байти, використовуючи деякі обіцянки на вході, особливо обіцянку, що всі непорожні рядки мають розділовий характер та пояснення.
  • Вдалося трохи більше пограти в гольф, врятувавши розділені струни від першого mapдзвінка та виконуючи деякі непотрібні stripфункції, засновані на обіцянці, що слова в поясненні завжди мають рівно один простір між ними. Крім того, " "призначається постійним зараз, оскільки я його так багато використовую.
  • Зв'язали обидва mapвиклики разом, використовуючи потужність функцій вищого порядку, тобто перший виклик карти lправильно встановить змінну довжини, навіть якщо вона викликається після оголошення функції помічника s. -4 байти.
  • Захоплені багаторядкові рядки замінити \nфактичними новими рядками, а також невеликий трюк, використовуючи ifнад потрійними операторами (коли joinвикликається масив зі nilзначеннями, вони стають порожніми рядками)
  • .joinможе бути замінено на *.

Думаю, це зараз слід виправити?
Значення чорнила

як це обгортання у 94?
Вен

Гаразд, тепер, коли у мене було більше часу на роботу над кодом, він завершується належним чином.
Значення чорнила

"Хоча пояснення може мати необмежену довжину, роздільник і код можуть мати лише комбіновану максимальну довжину 93 - 5 = 87символів. 5 символів - це проміжки між кодом і роздільником. Код і роздільник завжди будуть принаймні одним символом." Ваш розділ коду значно перевищує ліміт із 97 символами, тому програма має невизначене поведінку.
Значення чорнила

ах, добре помічений, має сенс!
Вен

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-ish: ліва частина =>є доступною, як і ..для решти блоків; і буде повернуто. Тут це елемент, розділений на k. Примітка: я використовую рядкову інтерполяцію, тому що /означає лише "розділити" буквальним рядком.

LS дозволяє використовувати і a-=/regexp/в цій лямбда (також працює з рядковими літералами): це лише цукор для .replaceдзвінка.

Нарешті, оператор >?=- комбінаторний >?-син, який повертає більше двох операндів.

LS має стилі Python / Haskell для розуміння, в них немає нічого фантазійного, окрім "рядків * разів", щоб повторити пробіл досить довго.

Це для розуміння слугує темою (див. Блок про каскади anove).

Потім ми зациклюємося на кожен елемент масиву (той, який ми щойно побудували з розумінням), і якщо будь-який рядок більший, ніж 93chars, ми знаходимо останній індекс, розбиваємо там і натискаємо відокремлену лінію прямо після цієї поточної ітерації ( ... Так що наступна ітерація знову розділиться, якщо лінія занадто велика).

Тільки остання річ фантазії 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
тому, хто виступав проти: відповідь фіксована.
Вень

2
Коли пояснення переповнено, вам потрібні нові рядки, щоб вирівняти їхні розділювальні символи з рештою, IIRC.
Значення чорнила

@KevinLau добре помічений, виправлений!
Вен

Чи можете ви також оновити свій приклад?
Значення чорнила

@KevinLau виконано.
Вен

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


Якщо хтось може зрозуміти, чому replace(" *"+s)це не працює, але replaceAll(" *"+s)я хотів би це почути - я не можу це зрозуміти.
CAD97

<багусь> 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

@nimi Сподіваємось, оновлення тепер покращують рішення.
Метт

@nimi Що ще ви помітили неправильно? У мене, мабуть, виникають проблеми з читанням останні пару днів.
Метт

Ні. Зараз є +1.
німі

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.