Uczyń to wyjaśnienie kodu jeszcze raz

17

Wprowadzenie

Większość golfistów tutaj dodaje wyjaśnienia do swoich zgłoszeń, dzięki czemu łatwiej zrozumieć, co się dzieje. Zazwyczaj linie kodowe idą po lewej stronie, a odpowiednie objaśnienie po prawej stronie z pewnego rodzaju separatorem. Aby wyglądać ładnie, separatory znajdują się w tej samej kolumnie. Również długi tekst wyjaśniający jest zwykle zawijany do następnego wiersza, więc czytelnicy nie muszą przewijać w poziomie, aby przeczytać wszystko.

Jednak, gdy chcesz edytować to wyjaśnienie, ponieważ stworzyłeś szalone gry w golfa, często spędzasz czas, aby wyjaśnić coś ładniej. Ponieważ jest to bardzo powtarzalne zadanie, chcesz do tego napisać program.

Wyzwanie

Biorąc pod uwagę kilka linii kodu z objaśnieniem i separator, wypisz ładnie sformatowany kod z objaśnieniem.

Przykład

Wejście

shM-crz1dc4. "ANDBYOROF # z = wejście

     rz1 # przekonwertować wejście na wielkie litery
    cd # podziel wejście na spacje
         c4. "ANDBYOROF # tworzy listę słów z zapakowanego ciągu, które należy zignorować
   - # odfiltruj te słowa
 hM # bierze tylko pierwszą literę wszystkich słów
s # połącz je w jeden ciąg

Wynik

shM-crz1dc4. "ANDBYOROF # z = wejście

     rz1 # przekonwertować wejście na wielkie litery
    cd # podziel wejście na spacje
         c4. "ANDBYOROF # tworzy listę słów z zapakowanego łańcucha, który będzie
                           # zignorowano
   - # odfiltruj te słowa
 hM # bierze tylko pierwszą literę wszystkich słów
s # połącz je w jeden ciąg

Jeden plik cookie dla pierwszego, który może dowiedzieć się, co robi ten kod.

Algorytm formatowania

  • Znajdź najdłuższą linię kodu (bez objaśnienia i spacji między kodem a separatorem).
  • Dodaj 5 spacji po tym wierszu kodu i dołącz odpowiedni separator z objaśnieniem. To jest teraz linia odniesienia.
  • Dopasuj co drugą linię do tej linii odniesienia, aby separatory znajdowały się w tej samej kolumnie.
  • Zawiń wszystkie linie dłuższe niż 93 znaki w nowy wiersz w następujący sposób:
    • Znajdź ostatnie słowo, którego koniec znajduje się w kolumnie 93 lub niższej.
    • Weź wszystkie słowa po tym i zawiń je do nowego wiersza z wiodącym separatorem i prawidłowymi odstępami. Spację między tymi dwoma słowami należy usunąć, więc pierwszy wiersz kończy się słowem, a drugi wiersz zaczyna się od jednego po separatorze.
    • Jeśli wynikowa linia jest nadal dłuższa niż 93 znaki, zrób to samo, aż każda linia będzie miała poniżej 94 znaków.

Notatki

  • Słowo składa się ze znaków spacji. Słowa są oddzielone pojedynczą spacją.
  • Zawijanie słów jest zawsze możliwe. Oznacza to, że żadne słowo nie jest tak długie, że uniemożliwiłoby to zawijanie.
  • Dane wejściowe będą zawierały tylko ASCII do wydrukowania i nie będą miały żadnych białych spacji
  • Separator pojawi się tylko raz na linię.
  • Chociaż wyjaśnienie może mieć nieograniczoną długość, separator i kod mogą mieć tylko łączną maksymalną długość 93 - 5 = 87znaków. 5 znaków to spacje między kodem a separatorem. Kod i separator zawsze będą miały co najmniej jeden znak.
  • Dane wejściowe mogą zawierać puste linie. Nie będą one nigdy zawierać żadnych znaków (z wyjątkiem nowego wiersza, jeśli weźmiesz dane jako ciąg wielowierszowy). Te puste wiersze również muszą być obecne na wyjściu.
  • Każda linia będzie zawierała kod, separator i wyjaśnienie. Wyjątkiem są puste linie.
  • Możesz wziąć dane wejściowe w dowolnym rozsądnym formacie, o ile nie są one wstępnie przetworzone. Podaj w odpowiedzi jasno, którego używasz.
  • Dane wyjściowe mogą być ciągiem wieloliniowym lub listą ciągów.

Zasady

Przypadki testowe

Format wejściowy tutaj to lista ciągów reprezentujących linie i pojedynczy ciąg dla separatora. Oba są oddzielone przecinkiem. Dane wyjściowe to lista ciągów znaków.

['shM-crz1dc4. "ANDBYOROF # z = input', '', 'rz1 # przekonwertować dane na wielkie litery', 'cd # podzielić wejście na spacje', 'c4." ANDBYOROF # stworzyć listę słów z zapakowanego ciąg, który należy zignorować ',' - # odfiltruj te słowa ',' hM # weź tylko pierwszą literę wszystkich słów ',' s # połącz je w jeden ciąg '], "#" -> [' shM-crz1dc4 . "ANDBYOROF # z = input ',' ',' rz1 # przekonwertować wejście na wielkie litery ',' cd # podzielić wejście na spacje ',' c4." ANDBYOROF # utwórz listę słów z zapakowanego ciągu znaków, który będzie " , „# ignored”, „- # odfiltruj te słowa ',' hM # weź tylko pierwszą literę wszystkich słów ',' s # połącz je w jeden ciąg ']
['codecodecode e # Explanation', 'sdf dsf sdf e # A Bardzo, bardzo, bardzo, bardzo, bardzo, bardzo, bardzo, bardzo długo, długo, długo, długo, długo, długo, długo, długo, długo, długie wyjaśnienie i to staje się coraz dłuższe ”,„ ”,„ niektóre więcej codee # i trochę więcej wyjaśnień ”],„ e # ”-> ['codecodecode e # Explanation', 'sdf dsf sdf e # A Bardzo bardzo bardzo bardzo bardzo bardzo bardzo bardzo bardzo bardzo długo długo długo długo', 'e # długo długie długie długie długie długie objaśnienia i ciągle się wydłużają ”,„ e # i dłużej ”,„ ”,„ trochę więcej kodu e # i trochę więcej wyjaśnień ”]

Happy Coding!

Denker
źródło
1
@Matt Wszystkie separatory są zawsze w kolumnie length of the longest code-line + 5. Dotyczyło to również wierszy, które zawierają tylko wyjaśnienie, ponieważ zostały zawinięte.
Denker
O mój boże, robię to źle przez ostatnie 3 godziny. Próbowałem owinąć długi kod i zostawić wyjaśnienia na długo ... Cóż, zaczynam od nowa. Przynajmniej teraz jest łatwiej. Dzięki. Dobrze to sformułowałeś ... Jestem po prostu głupi.
Matt
Zawijaj wszystkie wiersze dłuższe niż 93 znaki Czy to oznacza, że ​​kod, łącznie ze spacjami wiodącymi, nigdy nie będzie dłuższy niż 87 znaków?
Matt
@Matt Kod i separator nigdy nie będą dłuższe niż 87 znaków, ponieważ potrzebujemy 5 spacji między kodem a separatorem i jednego znaku dla wyjaśnienia.
Denker
1
Kod Pyth znajduje skrót dowolnego podanego ciągu. Wiedziałbym, bo to była odpowiedź na moje pytanie.
Aplet123

Odpowiedzi:

3

Rubinowy, 245 237 220 216 212 209 205 bajtów

Funkcja anonimowa. Całkiem podstawowe podejście (znajdź maksymalną długość, dodaj 5, a następnie wykonaj przetwarzanie w każdej linii, z rekurencją, aby poradzić sobie z zawijaniem) i może istnieć inne podejście, które oszczędza więcej bajtów.

Usunąłem wcześniej odpowiedź, która nie spełniała wszystkich wymagań; Nie chciałem mieć kodu z niepełną odpowiedzią jako odpowiedzi (otrzymywałem również głosowanie za niepełność), ale teraz powinien zrobić wszystko, o co pyta pytanie.

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

Dziennik zmian:

  • Zaoszczędzono kilka bajtów, wykorzystując niektóre obietnice na wejściu, szczególnie obietnicę, że wszystkie niepuste linie mają znak separatora i wyjaśnienie.
  • Udało mu się jeszcze trochę zagrać w golfa, zapisując podzielone łańcuchy od pierwszego mappołączenia i przyjmując niepotrzebne stripfunkcje w oparciu o obietnicę, że słowa w objaśnieniu zawsze mają dokładnie jedną spację między nimi. Ponadto " "jest teraz przypisany do stałej, ponieważ tak często jej używam.
  • Połączono oba mappołączenia razem, wykorzystując moc funkcji wyższego rzędu, co oznacza, że ​​pierwsze wywołanie mapy ustawi lpoprawnie zmienną długości, nawet jeśli zostanie wywołane po zadeklarowaniu funkcji pomocniczej s. -4 bajty.
  • Nadużywane ciągi wielowierszowe do zastąpienia \n rzeczywiste znaki nowego wiersza, a także mała sztuczka przy użyciu ifoperatorów trójskładnikowych (gdy joinwywoływana jest tablica z nilwartościami, stają się pustymi ciągami)
  • .joinnajwyraźniej można zastąpić *.
Wartość tuszu
źródło
Myślę, że należy to teraz naprawić?
Wartość tuszu
jak to się zawija na 94?
Ven
Dobra, teraz, kiedy miałem więcej czasu na pracę nad kodem, jest on poprawnie zawijany.
Wartość tuszu
„Chociaż wyjaśnienie może mieć nieograniczoną długość, separator i kod mogą mieć tylko łączną maksymalną długość 93 - 5 = 87znaków. 5 znaków to spacje między kodem a separatorem. Kod i separator zawsze będą miały co najmniej jeden znak.” Sekcja kodu przekroczyła limit (97 znaków), więc program ma niezdefiniowane zachowanie.
Wartość tuszu
ah, dobrze zauważony, ma sens!
Ven
9

LiveScript, 243 236 233 228 219 225 bajtów

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

Jak to działa: głównie jak kod Java. Zacznij od aliasingu długości (LiveScript pozwala tworzyć funkcje z operatorów za pomocą nawiasów). .=jest a = a.b- którego używamy tutaj do mapowania.

=> blabla ..to kaskadowa konstrukcja Smalltalk: lewa strona =>jest dostępna jako.. dla reszty bloku; i zostaną zwrócone. Tutaj jest to element podzielony na k. Uwaga: używam interpolacji ciągów, ponieważ /oznacza to tylko „dzielenie” za pomocą literału.

LS pozwala nam korzystać a-=/regexp/ tej lambdy (działa również z literałami łańcuchowymi): to tylko cukier na .replacerozmowę.

Wreszcie >?= jest >?operatorem kombinatoryjnym, który zwraca większy z dwóch operandów.

LS ma styl Python / Haskell do rozumienia, nie ma w nich nic szczególnego, z wyjątkiem „ciągów * razy”, aby wystarczająco długo powtarzać przestrzeń.

To dla zrozumienia służy jako temat (patrz blok o kaskadach powyżej).

Następnie zapętlamy każdy element tablicy (ten, który właśnie zbudowaliśmy ze zrozumieniem), a jeśli jakakolwiek linia jest większa niż 93 znaki, znajdujemy ostatni indeks, dzielimy się tam i pchamy oddzieloną linię zaraz po bieżącej iteracji ( ... Aby następna iteracja ponownie się podzieliła, jeśli linia jest zbyt duża).

Ostatnią rzeczą, tylko wyobraźnia a[j to]to seria (z j do końca), ale ponieważ używa metod macierzowych musimy dołączyć go z powrotem do łańcucha, który możemy zrobić za pomocą przeciążony *: *''.

przykład

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

wynik:

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
Ven
źródło
1
każdemu, kto przegłosował: odpowiedź jest ustalona.
Ven
2
Gdy wyjaśnienie się przepełni, potrzebujesz nowych wierszy, aby wyrównać ich znaki separatora z resztą, IIRC.
Wartość tuszu
@KevinLau dobrze zauważony, naprawiony!
Ven
Czy możesz również zaktualizować przykładowe dane wyjściowe?
Wartość tuszu
@KevinLau gotowe.
Ven
6

Java, 347 + 19 = 366 bajtów

Wymaga

import java.util.*;

Zatem +19 bajtów.

(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);}}

Pobiera w formacie f.accept(List<String> code, String seperator). Formaty w miejscu. Wersja, która tworzy i zwraca nową, List<String>byłaby łatwa do wdrożenia, ale kosztowała trochę bajtów.

Wcięte + przykładowe użycie:

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

... prawdopodobnie powinienem to samo przez to przejść: P

CAD97
źródło
Jeśli ktoś może dowiedzieć się, dlaczego replace(" *"+s)nie działa, ale replaceAll(" *"+s)czy chciałbym to usłyszeć - nie mogę tego zrozumieć.
97 CAD
<badguess> replaceużywa ciągów, ale replaceAllużywa wyrażeń regularnych . </badguess>
CalculatorFeline
@CatsAreFluffy dobrze, masz rację ! Nie wiem, jak nie zdawałem sobie z tego sprawy: P
97 CAD
Nie możesz usunąć nowej linii?
CalculatorFeline
Cóż, nowa linia może zostać usunięta z powodu wymaganych semi: s (które powinny być .s, ale cokolwiek)
CalculatorFeline
2

PowerShell, 224 217 235 bajtów

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}

Zaktualizowano logikę, aby określić maksymalną długość ciągu kodu. Zaktualizowano, aby umożliwić stosowanie wielu separatorów zawierających wyrażenia regularne meta.


Małe wyjaśnienie

To pobiera cały ciąg znaków nowej linii do wprowadzania.

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
}

Przykładowe wyniki z pewnym 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
źródło
@nimi Mam nadzieję, że aktualizacje są teraz lepszym rozwiązaniem.
Matt
@nimi Coś jeszcze zauważyłeś źle? Najwyraźniej mam problemy z czytaniem przez ostatnie kilka dni.
Matt
Nie. Teraz mają +1.
nimi
1

MATLAB, 270 265 262 bajtów

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

Program akceptuje dane wejściowe Iw postaci tablicy komórek zawierającej ciągi znaków, przy czym każdy element tablicy komórek jest osobną linią danych wejściowych. Akceptuje również drugie wejście, które wskazuje, jaki jest znak komentarza (tj #.). Funkcja zwraca łańcuch o wielu wierszach, który jest poprawnie sformatowany.

Krótkie wyjaśnienie

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

Przykładowe dane wejściowe

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,'#'));

Przykładowy wynik

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
źródło