Rendi questa spiegazione del codice piuttosto carina


17

introduzione

La maggior parte dei golfisti del codice qui aggiunge spiegazioni alle loro osservazioni, quindi è più facile capire cosa sta succedendo. Di solito le linee guida vanno a sinistra e la spiegazione corrispondente a destra con una sorta di separatore. Per renderlo carino, i separatori sono tutti sulla stessa colonna. Anche un lungo testo esplicativo viene di solito spostato alla riga successiva, quindi i lettori non devono scorrere in senso orizzontale per leggere tutto.

Tuttavia, quando vuoi modificare questa spiegazione perché hai fatto dei golf pazzi, spesso finisci per passare il tempo a rendere di nuovo la tua spiegazione. Poiché si tratta di un'attività molto ripetitiva, si desidera scrivere un programma per questo.

La sfida

Date diverse righe di codice con spiegazione e un separatore, genera il codice ben formattato con spiegazione.

Esempio

Ingresso

shM-crz1dc4. "ANDBYOROF # z = input

     rz1 # converte l'input in maiuscolo
    cd # suddivide l'input negli spazi
         c4. "ANDBYOROF # crea un elenco di parole da una stringa compressa che deve essere ignorata
   - # filtra queste parole
 hM # accetta solo la prima lettera di tutte le parole
s # li unisce in una stringa

Produzione

shM-crz1dc4. "ANDBYOROF # z = input

     rz1 # converte l'input in maiuscolo
    cd # suddivide l'input negli spazi
         c4. "ANDBYOROF # crea un elenco di parole da una stringa compressa che deve essere
                           # ignorato
   - # filtra queste parole
 hM # accetta solo la prima lettera di tutte le parole
s # li unisce in una stringa

Un cookie per il primo che può scoprire cosa fa questo codice.

L'algoritmo di formattazione

  • Trova la linea di codice più lunga (esclusa la spiegazione e gli spazi tra il codice e il separatore).
  • Aggiungi 5 spazi dopo questa riga di codice e aggiungi il separatore corrispondente con una spiegazione. Questa è ora la linea di riferimento.
  • Regola ogni altra linea su questa linea di riferimento, in modo che i separatori siano tutti nella stessa colonna.
  • Avvolgi tutte le righe più lunghe di 93 caratteri in una nuova riga nel modo seguente:
    • Trova l'ultima parola che termina alla colonna 93 o inferiore.
    • Prendi tutte le parole dopo questa e avvolgile in una nuova riga con il separatore principale e la spaziatura corretta. Lo spazio tra queste due parole deve essere eliminato, quindi la prima riga termina con un carattere di parola e la seconda riga inizia con una dopo il separatore.
    • Se la riga risultante è ancora più lunga di 93 caratteri, fai di nuovo lo stesso fino a quando ogni riga è inferiore a 94 caratteri.

Appunti

  • Una parola è composta da caratteri non bianchi. Le parole sono separate da un singolo spazio.
  • La parola a capo è sempre possibile. Ciò significa che nessuna parola è così lunga da rendere impossibile l'avvolgimento.
  • L'input conterrà solo ASCII stampabile e non avrà spazi bianchi finali
  • Il separatore apparirà una sola volta per riga.
  • Mentre la spiegazione può avere una lunghezza illimitata, il separatore e il codice possono avere solo una lunghezza massima combinata di 93 - 5 = 87caratteri. I 5 caratteri sono gli spazi tra il codice e il separatore. Il codice e il separatore avranno sempre almeno un carattere.
  • L'input può contenere righe vuote. Questi non conterranno mai alcun carattere (tranne una nuova riga se prendi l'input come stringa multilinea). Anche quelle righe vuote devono essere presenti nell'output.
  • Ogni riga avrà del codice, un separatore e una spiegazione. Le eccezioni sono righe vuote.
  • È possibile accettare l'input in qualsiasi formato ragionevole, purché non sia pre-elaborato. Spiega nella tua risposta quale usi.
  • L'output può essere una stringa su più righe o un elenco di stringhe.

Regole

Casi test

Il formato di input qui è un elenco di stringhe che rappresentano le righe e una singola stringa per il separatore. Entrambi sono separati da una virgola. L'output è un elenco di stringhe.

['shM-crz1dc4. "ANDBYOROF # z = input', '', 'rz1 # converte l'input in maiuscolo', 'cd # split input negli spazi', 'c4." ANDBYOROF # crea un elenco delle parole da un pacchetto stringa che deve essere ignorata ',' - # filtra quelle parole ',' hM # prende solo la prima lettera di tutte le parole ',' s # le unisce in una stringa '], "#" -> [' shM-crz1dc4 . "ANDBYOROF # z = input ',' ',' rz1 # converte input in maiuscolo ',' cd # split input onpace ',' c4." ANDBYOROF # crea un elenco di parole da una stringa compressa che deve essere ' , "# ignorato", "- # filtra queste parole ',' hM # prende solo la prima lettera di tutte le parole ',' s # le unisce in una stringa ']
['codecodecode e # Explanation', 'sdf dsf sdf e # A Molto molto molto molto molto molto molto molto molto lungo molto lungo lungo lungo lungo lungo lungo lungo lungo lungo lungo e continua ad allungarsi e allungarsi', '', 'alcuni più codice # e qualche altra spiegazione '], "e #" -> [' codecodecode e # Explanation ',' sdf dsf sdf e # A Molto molto molto molto molto molto molto molto molto lungo lungo lungo lungo ',' e # lungo long long long long long spiegazione e continua ad allungarsi ',' e # e long ',' ',' ancora un po 'di codice e # e qualche altra spiegazione']

Buona programmazione!


1
@Matt Tutti i separatori sono sempre nella colonna length of the longest code-line + 5. Questo valeva anche per le linee che contengono solo una spiegazione, perché sono state racchiuse.
Denker,

Oh mio Dio, sto facendo questo sbagliato in questo nelle ultime 3 ore. Stavo cercando di racchiudere il codice lungo e lasciare lunghe le spiegazioni ..... Bene, ricominciare da capo. Almeno ora è più facile. Grazie. L'hai detto bene ... Sono solo sciocco.
Matt,

Avvolgi tutte le righe di lunghezza superiore a 93 caratteri Significa che il codice, inclusi gli spazi iniziali, non sarà mai più lungo di 87 caratteri?
Matt,

@Matt Il codice e il separatore insieme non saranno mai più lunghi di 87 caratteri poiché abbiamo bisogno di 5 spazi tra il codice e il separatore e un carattere per la spiegazione.
Denker,

1
Il codice Pyth trova l'abbreviazione di una determinata stringa. Lo saprei perché quella era una risposta alla mia domanda.
Aplet123,

Risposte:


3

Rubino, 245 237 220 216 212 209 205 byte

Funzione anonima. Piuttosto approccio di base (per la lunghezza massima, aggiungere 5, poi fare l'elaborazione su ogni linea, con la ricorsione a che fare con il confezionamento), e ci potrebbe essere un altro approccio che consente di risparmiare più byte.

Ho eliminato la risposta in precedenza che non soddisfaceva tutti i requisiti; Io non voglio avere un codice di mezza risposto come una risposta (si stava facendo downvotes per essere incompleta troppo), ma dovrebbe fare di tutto la questione chiede, ora.

->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:

  • Hai salvato alcuni byte sfruttando alcune delle promesse nell'input, in particolare la promessa che tutte le righe non vuote hanno il carattere separatore e una spiegazione.
  • Riuscito a giocare un po 'più a golf salvando le stringhe divise dalla prima mapchiamata ed eliminando alcune stripfunzioni non necessarie basate sulla promessa che le parole nella spiegazione hanno sempre esattamente uno spazio tra loro. Inoltre, " "viene assegnato ad una costante da quando lo uso così tanto.
  • Incatenate entrambe le mapchiamate sfruttando la potenza delle funzioni di ordine superiore, il che significa che la prima chiamata della mappa imposterà lcorrettamente la variabile di lunghezza anche se viene chiamata dopo la dichiarazione della funzione di supporto s. -4 byte.
  • Stringhe multilinea abusate da sostituire \ncon nuove linee effettive, oltre a un piccolo trucco che utilizza ifoperatori ternari (quando joinviene chiamato su un array con nilvalori, diventano stringhe vuote)
  • .joinapparentemente può essere sostituito con a *.

Penso che dovrebbe essere risolto ora?
Value Ink

come si avvolge a 94?
Ven

Va bene, ora che ho avuto più tempo per lavorare sul codice, si avvolge in modo corretto.
Value Ink

"Mentre la spiegazione può avere una lunghezza illimitata, il separatore e il codice possono avere solo una lunghezza massima combinata di 93 - 5 = 87caratteri. I 5 caratteri sono gli spazi tra il codice e il separatore. Il codice e il separatore saranno sempre lunghi almeno un carattere." La sezione del codice supera di molto il limite, con 97 caratteri, quindi il programma ha un comportamento indefinito.
Value Ink

ah, ben individuato, ha un senso!
Ven

9

LiveScript, 243 236 233 228 219 225 byte

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

Come funziona: per lo più come il codice Java. Inizia con l'aliasing length (LiveScript consente di creare una funzione dagli operatori utilizzando le parentesi). .=è a = a.b- che usiamo qui per mappare.

=> blabla ..è il costrutto a cascata Smalltalk-ish: il lato sinistro di =>è accessibile come ..per il resto del blocco; e verrà restituita. Qui, è l'elemento di divisione su k. Nota: sto usando l'interpolazione di stringhe, perché /significa solo "dividere" con una stringa letterale.

LS ci permette di usare a-=/regexp/in questo lambda così (funziona anche con le stringhe): è solo zucchero per una .replacechiamata.

Infine, >?=è l' >?operatore combinatorio -assin, che restituisce il maggiore di due operandi.

LS ha / Haskell in stile Python per comprensioni, con niente di speciale in loro, tranne la "stringa * tempi" per ripetere lo spazio abbastanza a lungo.

Questo per comprensione funge da argomento (vedi il blocco sulle cascate).

Quindi eseguiamo il loop in ogni elemento dell'array (quello che abbiamo appena creato con la comprensione) e se una linea è più grande di 93chars, troviamo l'ultimo indice di, diviso lì, e spingiamo la linea separata subito dopo questa iterazione corrente ( ... In modo che la prossima iterazione si divida di nuovo se la linea è troppo grande).

Solo ultima cosa di fantasia a[j to]è un intervallo (da j fino alla fine), ma dal momento che utilizza metodi Array dobbiamo unire di nuovo a una stringa, che facciamo utilizzando sovraccaricati *: *''.

esempio

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

produzione:

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
a chiunque abbia annullato il voto: la risposta è fissa.
Ven

2
Quando una spiegazione trabocca, sono necessarie le nuove linee per allineare i loro caratteri di separazione con il resto, IIRC.
Value Ink

@KevinLau ben individuato, risolto!
Ven

Puoi aggiornare anche l'output di esempio?
Value Ink

@KevinLau done.
Ven

6

Java, 347 + 19 = 366 byte

Richiede

import java.util.*;

Quindi i +19 byte.

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

Prende nel formato f.accept(List<String> code, String seperator). Formati sul posto. Una versione che crea e restituisce una nuovaList<String> sarebbe banale da implementare ma costa alcuni byte.

Uso rientrato + esempio:

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

... Probabilmente dovrei farcela da solo: P


Se qualcuno riesce a capire perché replace(" *"+s)non funziona ma replaceAll(" *"+s)mi piacerebbe ascoltarlo, non riesco a capirlo.
CAD97

<badguess> replaceutilizza stringhe ma replaceAllusi espressioni regolari. </badguess>
CalculatorFeline

@CatsAreFluffy bene, siete sulla strada giusta ! Non so come non me ne fossi reso conto: P
CAD97

Non puoi rimuovere il ritorno a capo?
CalculatorFeline

Bene, la nuova riga può essere rimossa a causa dei semi: s richiesti (che dovrebbero essere .s ma qualunque cosa)
CalculatorFeline

2

PowerShell, 224 217 235 byte

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}

Aggiornata la logica per determinare la lunghezza massima della stringa di codice. Aggiornato per consentire più separatori che includono meta caratteri regex.


Piccola spiegazione

Questo accetta un'intera stringa delimitata da newline per l'input.

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
}

Output del campione con alcuni 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 Speriamo che gli aggiornamenti facciano ora una soluzione migliore.
Matt

@nimi C'è qualcos'altro che noti di sbagliato? Apparentemente ho problemi a leggere gli ultimi due giorni.
Matt

No. Adesso hai un +1.
nimi,

1

MATLAB, 270 265 262 byte

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

Il programma accetta l'input Isotto forma di un array di celle di stringhe in cui ciascun elemento dell'array di celle è una riga separata dell'input. Accetta anche un secondo input che indica quale sia il carattere del commento (cioè #). La funzione restituisce una stringa multilinea formattata correttamente.

Breve spiegazione

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

Esempio di input

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

Esempio di output

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.