Torne esta explicação de código bonita novamente

17

Introdução

A maioria dos jogadores de código aqui adiciona explicações aos envios, para que seja mais fácil entender o que está acontecendo. Normalmente, as linhas de código vão à esquerda e a explicação correspondente à direita com algum tipo de separador. Para torná-lo bonito, os separadores estão todos na mesma coluna. Além disso, o texto de explicação longo geralmente é agrupado na próxima linha, para que os leitores não precisem rolar horizontalmente para ler tudo.

No entanto, quando você deseja editar esta explicação porque criou alguns golfinhos malucos, muitas vezes acaba gastando tempo para torná-la bonita novamente. Como essa é uma tarefa muito repetitiva, você deseja escrever um programa para isso.

O desafio

Dadas várias linhas de código com explicação e um separador, imprima o código bem formatado com explicação.

Exemplo

Entrada

shM-crz1dc4. "ANDBYOROF # z = entrada

     rz1 # converte entrada para maiúscula
    cd # split input nos espaços
         c4. "ANDBYOROF # cria uma lista de palavras de uma sequência compactada que deve ser ignorada
   - # filtrar essas palavras
 hM # leva apenas a primeira letra de todas as palavras
s # junte-os em uma sequência

Resultado

shM-crz1dc4. "ANDBYOROF # z = entrada

     rz1 # converte entrada para maiúscula
    cd # split input nos espaços
         c4. "ANDBYOROF # cria uma lista de palavras de uma string empacotada que deve ser
                           # ignorado
   - # filtrar essas palavras
 hM # leva apenas a primeira letra de todas as palavras
s # junte-os em uma sequência

Um cookie para o primeiro que pode descobrir o que esse código faz.

O algoritmo de formatação

  • Encontre a linha de código mais longa (excluindo a explicação e os espaços entre o código e o separador).
  • Adicione 5 espaços após essa linha de código e acrescente o separador correspondente com a explicação. Agora é a linha de referência.
  • Ajuste todas as outras linhas a essa linha de referência, para que os separadores estejam todos na mesma coluna.
  • Quebra todas as linhas com mais de 93 caracteres em uma nova linha da seguinte maneira:
    • Encontre a última palavra cujo final está na coluna 93 ou inferior.
    • Pegue todas as palavras após esta e envolva-as em uma nova linha com o separador à esquerda e o espaçamento correto. O espaço entre essas duas palavras deve ser excluído; portanto, a primeira linha termina com um caractere de palavra e a segunda linha inicia com uma após o separador.
    • Se a linha resultante ainda tiver mais de 93 caracteres, faça o mesmo novamente até que cada linha esteja abaixo de 94 caracteres.

Notas

  • Uma palavra consiste em caracteres que não são espaços em branco. As palavras são separadas por um único espaço.
  • A quebra de linha é sempre possível. Isso significa que nenhuma palavra é tão longa que tornaria a embalagem impossível.
  • A entrada conterá apenas ASCII imprimível e não terá espaços em branco à direita
  • O separador aparecerá apenas uma vez por linha.
  • Embora a explicação possa ter tamanho ilimitado, o separador e o código podem ter apenas um comprimento máximo combinado de 93 - 5 = 87caracteres. Os 5 caracteres são os espaços entre o código e o separador. O código e o separador sempre terão pelo menos um caractere.
  • A entrada pode conter linhas vazias. Esses nunca conterão nenhum caractere (exceto uma nova linha se você receber a entrada como sequência de múltiplas linhas). Essas linhas vazias também devem estar presentes na saída.
  • Cada linha terá algum código, um separador e uma explicação. Exceções são linhas vazias.
  • Você pode receber a entrada em qualquer formato razoável, desde que não seja pré-processada. Deixe claro em sua resposta qual você usa.
  • A saída pode ser uma sequência multilinha ou uma lista de sequências.

Regras

  • Função ou programa completo permitido.
  • Regras padrão para entrada / saída.
  • Aplicam-se brechas padrão .
  • Isso é , portanto, a menor contagem de bytes vence. O desempate é uma submissão anterior.

Casos de teste

O formato de entrada aqui é uma lista de cadeias que representam as linhas e uma única cadeia para o separador. Ambos são separados por vírgula. Saída é uma lista de strings.

['shM-crz1dc4. "ANDBYOROF # z = entrada', '', 'rz1 # converte entrada em maiúscula', 'cd # entrada dividida em espaços', 'c4." ANDBYOROF # cria uma lista de palavras de um pacote string que deve ser ignorada ',' - # filtrar essas palavras ',' hM # pega apenas a primeira letra de todas as palavras ',' s # junta-as a uma string '], "#" -> [' shM-crz1dc4 . "ANDBYOROF # z = entrada ',' ',' rz1 # converte entrada em maiúscula ',' cd # entrada dividida em espaços ',' c4." ANDBYOROF # cria uma lista de palavras de uma sequência compactada que deve ser ' , '# ignorado', '- # filtra essas palavras ',' hM # pega apenas a primeira letra de todas as palavras ',' s # junta-as a uma sequência ']
['codecodecode e # Explanation', 'sdf dsf sdf e # A Explicação Muito, muito, muito muito muito muito muito muito muito longo longo longo longo longo longo longo longo longo longo longo explicação longa e cada vez mais longa' '' ',' alguns mais código # e mais algumas explicações '], "e #" -> [' codecodecode e # Explicação ',' sdf dsf sdf e # A Muito muito muito muito muito muito muito muito muito muito muito muito tempo muito tempo muito longo ',' e # long longo longo longo longo longo explicação e ele fica cada vez mais longo ',' e # e mais ',' ',' mais código e # e mais explicação ']

Feliz codificação!

Denker
fonte
11
@ Matt Todos os separadores estão sempre na coluna length of the longest code-line + 5. Isso também se aplicava a linhas que contêm apenas uma explicação, porque foram quebradas.
Denker 24/03
Oh meu Deus, eu tenho feito isso errado nas últimas 3 horas. Eu estava tentando quebrar o código longo e deixando as explicações longas ... Bem, começando de novo. Pelo menos agora é mais fácil. Obrigado. Você expressou bem ... Eu sou apenas bobo.
Matt
Quebrar todas as linhas com mais de 93 caracteres Isso significa que o código, incluindo espaços à esquerda, nunca terá mais de 87 caracteres?
Matt
@ Mat O código e o separador juntos nunca terão mais de 87 caracteres, pois precisamos de 5 espaços entre o código e o separador e um caractere para a explicação.
Denker
11
O código Pyth encontra a abreviação de qualquer string. Eu saberia porque essa era uma resposta para minha pergunta.
Aplet123

Respostas:

3

Ruby, 245 237 220 216 212 209 205 bytes

Função anônima. Abordagem bastante básica (encontre comprimento máximo, adicione 5 e faça o processamento em cada linha, com recursão para lidar com quebra automática) e pode haver outra abordagem que economize mais bytes.

Excluí a resposta anterior que não atendia a todos os requisitos; Eu não queria ter um código semi-respondido como resposta (também estava diminuindo a votação por estar incompleto), mas ele deve fazer tudo o que a pergunta pede agora.

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

  • Salvei alguns bytes aproveitando algumas das promessas na entrada, especialmente a promessa de que todas as linhas não vazias têm o caractere separador e uma explicação.
  • Conseguiu jogar um pouco mais, salvando as cordas divididas da primeira mapchamada e removendo algumas desnecessáriasstrip funções base na promessa de que as palavras na explicação sempre têm exatamente um espaço entre elas. Além disso, " "é atribuído a uma constante agora, já que eu a uso muito.
  • Associe as duas mapchamadas em conjunto, aproveitando o poder das funções de ordem superior, o que significa que a primeira chamada de mapa definirá a variável length lcorretamente, mesmo que seja chamada após a declaração da função auxiliars . -4 bytes.
  • Cadeias de \nlinhas múltiplas abusadas para substituir por novas linhas reais, além de um pequeno truque usando ifoperadores ternários (quando joinchamados em uma matriz com nilvalores, eles se tornam cadeias vazias)
  • .joinaparentemente pode ser substituído por um *.
Value Ink
fonte
Eu acho que deve ser corrigido agora?
Value Ink
como isso termina em 94?
Ven
Tudo bem, agora que eu tive mais tempo para trabalhar no código, ele envolve corretamente.
Value Ink
"Embora a explicação possa ter tamanho ilimitado, o separador e o código podem ter apenas um comprimento máximo combinado de 93 - 5 = 87caracteres. Os 5 caracteres são os espaços entre o código e o separador. O código e o separador sempre terão pelo menos um caractere." Sua seção de código está muito além do limite, com 97 caracteres, portanto o programa tem um comportamento indefinido.
Value Ink
ah, bem visto, faz sentido!
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

Como funciona: principalmente como o código Java. Comece com o tamanho do alias (o LiveScript permite criar uma função dos operadores usando parênteses). .=é a = a.b- que usamos aqui para mapear.

=> blabla ..é a construção em cascata Smalltalk-ish: o lado esquerdo =>é acessível como ..no resto do bloco; e será devolvido. Aqui, é o elemento dividido em k. Nota: estou usando interpolação de string, porque /significa apenas "split" com uma string literal.

O LS também nos permite usar a-=/regexp/neste lambda (também funciona com literais de string): é apenas açúcar para uma .replacechamada.

Finalmente, o >?=é o >?operador combinator -assin, que retorna o maior de dois operandos.

O LS tem estilo Python / Haskell para compreensão, sem nada sofisticado, exceto o "string * times" para repetir o espaço por tempo suficiente.

Isso para compreensão serve como o tópico (veja o bloco sobre cascatas acima).

Em seguida, fazemos um loop em cada elemento da matriz (aquele que acabamos de construir com a compreensão) e, se alguma linha for maior que 93chars, encontramos o último índice de, dividido lá e pressionamos a linha separada logo após a iteração atual ( ... Para que a próxima iteração seja dividida novamente se a linha for muito grande).

A última coisa que chama a atenção a[j to]é um intervalo (de j até o final), mas como ele usa os métodos Array, é necessário juntá-lo novamente a uma string, o que fazemos usando sobrecarregado *:*'' .

exemplo

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

resultado:

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
fonte
11
para quem recusou: a resposta é fixa.
Ven
2
Quando uma explicação é excedida, você precisa das novas linhas para alinhar seus caracteres separadores com o restante, IIRC.
Value Ink
@KevinLau bem avistado, consertado!
Ven
Você também pode atualizar seu exemplo de saída?
valor é de
@KevinLau done.
Ven
6

Java, 347 + 19 = 366 bytes

Requer

import java.util.*;

Assim, os +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);}}

Toma no formato f.accept(List<String> code, String seperator). Formatos no local. Uma versão que cria e retorna um novo List<String>seria trivial de implementar, mas custaria alguns bytes.

Recuo + uso de exemplo:

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

... Eu provavelmente deveria executar isso sozinho: P

CAD97
fonte
Se alguém pode descobrir por que replace(" *"+s)não está funcionando, mas replaceAll(" *"+s)é que eu adoraria ouvi-lo - não consigo descobrir.
CAD97
<badguess> replaceusa cadeias, mas replaceAllusa expressões regulares. </badguess>
CalculatorFeline
@CatsAreFluffy bem, você está correto ! Não sei como eu não percebi isso: P
CAD97 23/03
Você não pode remover a nova linha?
CalculatorFeline
Bem, a nova linha pode ser removido por causa do necessário semi: s (que deve ser .s, mas qualquer que seja)
CalculatorFeline
2

PowerShell, 224 217 235 bytes

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}

Atualizado a lógica para determinar o tamanho máximo da sequência de códigos. Atualizado para permitir vários separadores que incluem meta caracteres regex.


Pouca explicação

Isso inclui uma string delimitada por uma nova linha inteira para entrada.

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
}

Exemplo de saída com algum 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
fonte
@nimi Espero que as atualizações agora façam uma solução melhor.
Matt
@nimi Mais alguma coisa que você notou de errado? Aparentemente, estou tendo problemas para ler os últimos dois dias.
Matt
Não. Agora tenha um +1.
N
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

O programa aceita a entrada Ina forma de uma matriz de células, em que cada elemento da matriz de células é uma linha separada da entrada. Também aceita uma segunda entrada que indica qual é o caractere de comentário (ou seja #). A função retorna uma seqüência de várias linhas que está formatada corretamente.

Breve explicação

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

Exemplo de entrada

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

Saída de exemplo

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
fonte