Machen Sie diese Code-Erklärung noch einmal hübsch

17

Einführung

Die meisten Code-Golfer hier fügen Erklärungen zu ihren Einsendungen hinzu, so dass es einfacher ist zu verstehen, was los ist. In der Regel werden die Codelines links und die entsprechende Erklärung rechts mit einer Art Trennzeichen angezeigt. Damit es hübsch aussieht, befinden sich die Trennzeichen in derselben Spalte. Auch langer Erklärungstext wird normalerweise in die nächste Zeile umgebrochen, damit die Leser nicht horizontal scrollen müssen, um alles zu lesen.

Wenn Sie diese Erklärung jedoch bearbeiten möchten, weil Sie einige verrückte Golfspiele gemacht haben, verbringen Sie häufig Zeit damit, Ihre Erklärung wieder hübsch zu machen. Da dies eine sehr sich wiederholende Aufgabe ist, möchten Sie ein Programm dafür schreiben.

Die Herausforderung

Geben Sie bei mehreren Codezeilen mit Erklärung und einem Trennzeichen den gut formatierten Code mit Erklärung aus.

Beispiel

Eingang

shM-crz1dc4. "ANDBYOROF # z = Eingabe

     rz1 # konvertiert die Eingabe in Großbuchstaben
    CD # Split-Eingabe für Leerzeichen
         c4. "ANDBYOROF # Erstellt eine Liste der Wörter aus einer gepackten Zeichenfolge, die ignoriert werden soll
   - # diese Wörter herausfiltern
 hM # nimm nur den ersten Buchstaben aller Wörter
s # füge sie zu einer Zeichenkette zusammen

Ausgabe

shM-crz1dc4. "ANDBYOROF # z = Eingabe

     rz1 # konvertiert die Eingabe in Großbuchstaben
    CD # Split-Eingabe für Leerzeichen
         c4. "ANDBYOROF # Erstelle eine Liste der Wörter aus einer gepackten Zeichenkette, die sein soll
                           # ignoriert
   - # diese Wörter herausfiltern
 hM # nimm nur den ersten Buchstaben aller Wörter
s # füge sie zu einer Zeichenkette zusammen

Ein Cookie für den ersten, der herausfinden kann, was dieser Code bewirkt.

Der Formatierungsalgorithmus

  • Suchen Sie die längste Codezeile (ohne die Erklärung und die Leerzeichen zwischen Code und Trennzeichen).
  • Fügen Sie nach dieser Codezeile 5 Leerzeichen ein und fügen Sie das entsprechende Trennzeichen mit Erläuterung hinzu. Dies ist jetzt die Referenzlinie.
  • Passen Sie jede zweite Zeile an diese Referenzzeile an, sodass sich die Trennzeichen alle in derselben Spalte befinden.
  • Brechen Sie alle Zeilen, die länger als 93 Zeichen sind, wie folgt in eine neue Zeile ein:
    • Suchen Sie das letzte Wort, dessen Ende in Spalte 93 oder niedriger steht.
    • Nehmen Sie alle Wörter nach diesem und setzen Sie sie mit dem führenden Trennzeichen und dem richtigen Abstand in eine neue Zeile. Das Leerzeichen zwischen diesen beiden Wörtern muss gelöscht werden, sodass die erste Zeile mit einem Wortzeichen endet und die zweite Zeile mit einem nach dem Trennzeichen beginnt.
    • Wenn die resultierende Zeile immer noch länger als 93 Zeichen ist, wiederholen Sie dies, bis jede Zeile weniger als 94 Zeichen enthält.

Anmerkungen

  • Ein Wort besteht aus Nicht-Leerzeichen. Wörter werden durch ein einzelnes Leerzeichen getrennt.
  • Der Zeilenumbruch ist immer möglich. Dies bedeutet, dass kein Wort so lang ist, dass es das Umwickeln unmöglich machen würde.
  • Die Eingabe enthält nur druckbares ASCII und keine nachgestellten Leerzeichen
  • Das Trennzeichen wird nur einmal pro Zeile angezeigt.
  • Während die Erklärung eine unbegrenzte Länge haben kann, können das Trennzeichen und der Code nur eine kombinierte maximale Länge von 93 - 5 = 87Zeichen haben. Die 5 Zeichen sind die Leerzeichen zwischen Code und Trennzeichen. Code und Trennzeichen bestehen immer aus mindestens einem Zeichen.
  • Die Eingabe kann Leerzeilen enthalten. Diese enthalten niemals Zeichen (mit Ausnahme von Zeilenumbrüchen, wenn Sie Eingaben als mehrzeilige Zeichenfolge vornehmen). Diese Leerzeilen müssen auch in der Ausgabe vorhanden sein.
  • Jede Zeile enthält einen Code, ein Trennzeichen und eine Erklärung. Ausnahmen sind Leerzeilen.
  • Sie können die Eingabe in einem angemessenen Format vornehmen, solange sie nicht vorverarbeitet wird. Stellen Sie in Ihrer Antwort klar, welche Sie verwenden.
  • Die Ausgabe kann eine mehrzeilige Zeichenfolge oder eine Liste von Zeichenfolgen sein.

Regeln

  • Funktion oder Vollprogramm erlaubt.
  • Standardregeln für die Eingabe / Ausgabe.
  • Es gelten Standardlücken .
  • Dies ist , also gewinnt die niedrigste Byte-Anzahl. Tiebreaker ist eine frühere Vorlage.

Testfälle

Das Eingabeformat ist hier eine Liste mit Zeichenfolgen, die die Zeilen darstellen, und eine einzelne Zeichenfolge für das Trennzeichen. Beide sind durch ein Komma getrennt. Die Ausgabe ist eine Liste von Zeichenfolgen.

['shM-crz1dc4. "ANDBYOROF # z = Eingabe', '', 'rz1 # Eingabe in Großbuchstaben konvertieren', 'cd # Eingabe in Leerzeichen aufteilen', 'c4." ANDBYOROF # Erstellt eine Liste der Wörter aus einem gepackten Zeichenkette, die ignoriert werden soll ',' - # filtere diese Wörter heraus ',' hM # nimm nur den ersten Buchstaben aller Wörter ',' s # füge sie zu einer Zeichenkette zusammen '], "#" -> [' shM-crz1dc4 . "ANDBYOROF # z = Eingabe ',' ',' rz1 # Eingabe in Großbuchstaben umwandeln ',' cd # Eingabe in Leerzeichen aufteilen ',' c4." ANDBYOROF # Eine Liste der Wörter aus einer gepackten Zeichenfolge erstellen, die ' , '# ignoriert', '- # filtere diese Wörter heraus ',' hM # nimm nur den ersten Buchstaben aller Wörter ',' s # verbinde sie zu einer Zeichenkette ']
['codecodecode e # Erklärung', 'sdf dsf sdf e # Eine sehr sehr sehr sehr sehr sehr sehr lange lange lange lange lange lange lange lange lange lange lange Erklärung und es wird immer länger', '', 'einige mehr codee # und etwas mehr erklärung '], "e #" -> [' codecodecode e # erklärung ',' sdf dsf sdf e # A Sehr sehr sehr sehr sehr sehr sehr lang lang lang lang lang ',' e # lang lange lange lange lange lange Erklärung und es wird immer länger ',' e # und länger ',' ',' etwas mehr Code e # und etwas mehr Erklärung ']

Viel Spaß beim Codieren!

Denker
quelle
1
@Matt Alle Trennzeichen stehen immer in der Spalte length of the longest code-line + 5. Dies gilt auch für Zeilen, die nur eine Erklärung enthalten, weil sie umbrochen wurden.
Denker
Oh mein Gott, ich habe das in den letzten 3 Stunden falsch gemacht. Ich habe versucht, langen Code zu verpacken und die Erklärungen lange zu belassen ..... Nun fange ich von vorne an. Zumindest ist es jetzt einfacher. Vielen Dank. Du hast es gut formuliert ... Ich bin nur albern.
Matt
Alle Zeilen umbrechen, die länger als 93 Zeichen sind Bedeutet das, dass der Code einschließlich der führenden Leerzeichen nie länger als 87 Zeichen sein wird?
Matt
@Matt Der Code und das Trennzeichen zusammen dürfen nie länger als 87 Zeichen sein, da zwischen Code und Trennzeichen 5 Leerzeichen und ein Zeichen für die Erklärung erforderlich sind.
Denker
1
Der Pyth-Code findet die Abkürzung einer bestimmten Zeichenfolge. Ich würde es wissen, weil das eine Antwort auf meine Frage war.
Aplet123

Antworten:

3

Ruby, 245 237 220 216 212 209 205 Bytes

Anonyme Funktion. Ziemlich grundlegender Ansatz (maximale Länge finden, 5 addieren, dann Verarbeitung in jeder Zeile durchführen, mit Rekursion, um den Zeilenumbruch zu behandeln) und es könnte einen anderen Ansatz geben, der mehr Bytes spart.

Ich habe die Antwort zuvor gelöscht, die nicht alle Anforderungen erfüllte. Ich wollte keinen halb beantworteten Code als Antwort haben (es wurde auch schlecht bewertet, weil er unvollständig war), aber er sollte jetzt alles tun, was die Frage verlangt.

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

Änderungsprotokoll:

  • Einige Bytes wurden gespart, indem einige der Versprechen in der Eingabe genutzt wurden, insbesondere das Versprechen, dass alle nicht leeren Zeilen das Trennzeichen und eine Erklärung haben.
  • Schaffte es, ein bisschen mehr Golf zu spielen, indem die geteilten Saiten vom ersten mapAufruf an gespeichert und einige unnötige stripFunktionen entfernt wurden, basierend auf dem Versprechen, dass die Wörter in der Erklärung immer genau ein Leerzeichen dazwischen haben. Außerdem " "ist jetzt eine Konstante zugeordnet, da ich sie so oft benutze.
  • Verkettet beide mapAufrufe miteinander, indem die Leistungsfähigkeit von Funktionen höherer Ordnung genutzt wird. Dies bedeutet, dass der erste Kartenaufruf die lLängenvariable auch dann korrekt festlegt, wenn sie nach der Deklaration der Hilfsfunktion aufgerufen wird s. -4 Bytes.
  • Missbrauchte mehrzeilige Zeichenfolgen zum Ersetzen \ndurch tatsächliche Zeilenumbrüche sowie ein kleiner Trick mit ifüber ternären Operatoren (wenn joinein Array mit nilWerten aufgerufen wird , werden sie zu leeren Zeichenfolgen)
  • .joinkann anscheinend durch a ersetzt werden *.
Wert Tinte
quelle
Ich denke, es sollte jetzt behoben werden?
Wert Tinte
Wie endet das bei 94?
Ven
Alles klar, jetzt, da ich mehr Zeit hatte, um an dem Code zu arbeiten, wird er ordnungsgemäß umbrochen.
Wert Tinte
"Während die Erklärung eine unbegrenzte Länge haben kann, können das Trennzeichen und der Code nur eine kombinierte maximale Länge von 93 - 5 = 87Zeichen haben. Die 5 Zeichen sind die Leerzeichen zwischen Code und Trennzeichen. Code und Trennzeichen werden immer mindestens ein Zeichen lang sein." Ihr Codeabschnitt ist mit 97 Zeichen weit über dem Limit, sodass das Programm ein undefiniertes Verhalten aufweist.
Wert Tinte
Ah, gut gesehen, macht Sinn!
Ven
9

LiveScript, 243 236 233 228 219 225 Bytes

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

So funktioniert es: Meistens wie der Java-Code. Beginnen Sie mit Aliasing-Länge (LiveScript ermöglicht das Erstellen einer Funktion aus Operatoren mithilfe von Klammern). .=ist a = a.b- was wir hier verwenden, um abzubilden.

=> blabla ..ist das Smalltalk-ish-Kaskadenkonstrukt: die linke Seite von =>ist zugänglich wie ..für den Rest des Blocks; und wird zurückgegeben. Hier ist es das Element, das auf k aufgeteilt ist. Hinweis: Ich verwende die Zeichenfolgeninterpolation, da dies /nur "Teilen" mit einer Literalzeichenfolge bedeutet.

LS erlaubt es uns auch a-=/regexp/in diesem Lambda zu verwenden (funktioniert auch mit String-Literalen): Es ist nur Zucker für einen .replaceAnruf.

Schließlich ist das >?=der kombinatorische >?-assin-Operator, der den größeren von zwei Operanden zurückgibt.

LS hat einen Python / Haskell-Stil für das Verständnis, in dem nichts Besonderes vorkommt, außer die "string * times", um das Leerzeichen lange genug zu wiederholen.

Dies dient zum Verständnis als Thema (siehe Block über Kaskaden weiter oben).

Wir durchlaufen dann jedes Element des Arrays (das, das wir gerade mit dem Verständnis erstellt haben), und wenn eine Zeile größer als 93 Zeichen ist, finden wir den letzten Index von, teilen ihn dort auf und verschieben die getrennte Zeile direkt nach dieser aktuellen Iteration ( ... Damit die nächste Iteration wieder geteilt wird, wenn die Zeile zu groß ist).

Nur letzte , was Phantasie a[j to]ist ein Bereich (von j bis zum Ende), aber da es Array Methoden verwendet haben wir es wieder in einen String zu verbinden, die wir überlasten tun Verwendung *: *''.

Beispiel

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

Ausgabe:

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
quelle
1
an wen das runtergestimmt hat: die antwort steht fest.
Ven
2
Wenn eine Erklärung überläuft, müssen Sie die neue (n) Zeile (n) verwenden, um die Trennzeichen am Rest IIRC auszurichten.
Wert Tinte
@ KevinLau gut gesehen, behoben!
Ven
Können Sie auch Ihre Beispielausgabe aktualisieren?
Wert Tinte
@ KevinLau fertig.
Ven
6

Java, 347 + 19 = 366 Bytes

Benötigt

import java.util.*;

Also die +19 Bytes.

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

Nimmt das Format auf f.accept(List<String> code, String seperator). Formate vorhanden. Eine Version, die eine neue erstellt und zurückgibt List<String>, ist zwar einfach zu implementieren, kostet jedoch einige Bytes.

Einrückung + Beispielverwendung:

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

... sollte ich das wohl durchgehen lassen: P

CAD97
quelle
Wenn jemand herausfinden kann, warum replace(" *"+s)es nicht funktioniert, replaceAll(" *"+s)ich es aber gerne hören würde, kann ich es nicht herausfinden.
CAD97
<badguess> replaceverwendet Strings, aber replaceAllRegexes. </ badguess>
CalculatorFeline
@CatsAreFluffy na du hast recht ! Ich weiß nicht, wie ich das nicht realisiert habe: P
CAD97
Können Sie den Zeilenumbruch nicht entfernen?
CalculatorFeline
Nun, die Newline kann wegen der erforderlichen Semi entfernt werden: s (die sein sollte .s aber was auch immer)
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}

Die Logik wurde aktualisiert, um die maximale Länge der Codezeichenfolge zu bestimmen. Aktualisiert, um mehrere Trennzeichen zuzulassen, die reguläre Metazeichen enthalten.


Kleine Erklärung

Dies nimmt eine durch Zeilenumbrüche getrennte Zeichenfolge für die Eingabe auf.

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
}

Beispielausgabe mit etwas 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
quelle
@nimi Hoffentlich sorgen die Updates jetzt für eine bessere Lösung.
Matt
@nimi Ist dir sonst noch etwas aufgefallen? Ich habe anscheinend Probleme, die letzten Tage zu lesen.
Matt
Nein, jetzt haben Sie eine +1.
Nimi
1

MATLAB, 270 265 262 Bytes

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

Das Programm akzeptiert die Eingabe Iin Form eines Zellenarrays von Zeichenfolgen, wobei jedes Element des Zellenarrays eine separate Zeile der Eingabe ist. Es akzeptiert auch eine zweite Eingabe, die angibt, was das Kommentarzeichen ist (dh #). Die Funktion gibt eine mehrzeilige Zeichenfolge zurück, die ordnungsgemäß formatiert ist.

Kurze Erklärung

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

Beispiel Eingabe

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

Beispielausgabe

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
quelle