Converter chaves para chave direita (chave triste)

26

Colchete à direita é um estilo de colchete de código no qual colchetes e ponto e vírgula estão todos alinhados a um único ponto no lado direito de um arquivo.

Imagem de exemplo, vá aqui

Geralmente, isso é considerado uma má prática, por várias razões.

O desafio

Pegue uma sequência de várias linhas através de qualquer método e converta o estilo da chave para Chave à direita.

Para esse desafio, você só precisa trabalhar com código Java; no entanto, teoricamente, ele deve funcionar com qualquer código que use chaves e ponto e vírgula.

Você deve pegar todos os {};caracteres em uma linha, com qualquer quantidade de espaço em branco entre eles. POR EXEMPLO. }}, ; } }\n\t\t}E alinhá-los no lado direito do arquivo através do uso de espaço em branco.

por exemplo:

a {
b;
{c

Deve se tornar

a {
b ;{
c

Ou, de maneira mais abstrata, empurre todo e qualquer espaço em branco da esquerda de todos os {};caracteres para a direita.

O recuo das linhas deve ser preservado. As linhas que contêm apenas espaço em branco após o movimento dos {};caracteres podem opcionalmente ser removidas.

Por exemplo:

a{
    b{
        c;
    }
}
d;

Pode tornar-se

a        {
    b    {
        c;}}
d        ;

ou

a        {
    b    {
        c;}}


d        ;

Empurrado para a direita refere-se a todos os {}; caracteres sendo alinhados a um ponto não menor que a linha mais longa. Qualquer quantidade de espaço depois disso é aceitável.

Portanto, todos os itens abaixo são aceitáveis:

a {
bc;

a  {
bc ;

a   {
bc  ;

etc ...

Linhas em qualquer código podem conter {};caracteres entre outros caracteres que não sejam espaços em branco, o tratamento deste caso não é necessário, embora se você quiser, deixe-os no lugar. As linhas também podem não conter {};caracteres, e isso deve ser tratado corretamente. Como é mostrado abaixo.

a {
b ;
c
d }

Como não queremos que a Revisão de código veja as coisas horríveis que estamos fazendo, você precisa tornar seu código o menor possível.

Exemplos / casos de teste

Java genérico

public class HelloWorld{
       public static void main(String[] args){
           System.out.println("Hello, World!");
       }
}

torna-se...

public class HelloWorld                        {
    public static void main(String[] args)     {
        System.out.println("Hello, World!")    ;}}

A própria imagem

public class Permuter{
    private static void permute(int n, char[] a){
        if (n == 0){
            System.out.println(String.valueOf(a));
        }else{
            for (int i=0; i<= n; i++){
                permute(n-1, a);
                swap(a, n % 2 == 0 ? i : 0, n);
            }
        }
    }
    private static void swap(char[] a, int i, int j){
        char saved = a[i];
        a[i] = a[j];
        a[j] = saved;
    }
}

torna-se...

public class Permuter                                {
    private static void permute(int n, char[] a)     {
        if (n == 0)                                  {
            System.out.println(String.valueOf(a))    ;}
        else                                         {
            for (int i=0; i<= n; i++)                {
                permute(n-1, a)                      ;
                swap(a, n % 2 == 0 ? i : 0, n)       ;}}}
    private static void swap(char[] a, int i, int j) {
        char saved = a[i]                            ;
        a[i] = a[j]                                  ;
        a[j] = saved                                 ;}}

Python não tão perfeitamente genérico

Para contraste

def Main():
    print("Hello, World!");

Main();

torna-se...

def Main():
    print("Hello, World!")    ;
Main()                        ;

Notas

  • Aplicam-se brechas padrão
  • IO padrão se aplica
  • Isso é , e o programa mais curto em bytes vence!
  • Não sou responsável por danos relacionados à programação no estilo Right Hand Brace
  • Diverta-se!

Editar notas

Eu reformulei os detalhes do desafio. Espero não ter quebrado a visão de ninguém sobre as regras, garanto que não foi intencional. Essa deve ser uma especificação muito mais clara e menos conflitante.

ATaco
fonte
Qual é o veredicto em linhas com vários pontos e vírgulas? Algo comoint a=0;System.out.println(a);
Value Ink
2
Essa pode não ser a melhor imagem para o desafio, se não precisarmos lidar com loops como na imagem de amostra?
Dennis
1
Parece que a imagem em questão veio do presente exemplo , o que foi seguido por este seguimento , que tem exemplos mais complexos
Raio Toal
2
Poderia ficar mais claro que você deseja que os ;{}caracteres sejam reunidos se estiverem em linhas separadas (isso é claro apenas no exemplo, não nas regras, e, de fato, se uma linha consiste em \t}preservar o recuo, isso significa não avançar }até o fim da linha anterior)
Chris H
2
Bom Deus, por favor, diga-me que ninguém faz isso na prática para uma linguagem detalhada como Java ._.
Urna de polvo mágico

Respostas:

5

Utilitários V + Bash, 64 62 61 60 62 bytes

1 byte salvo graças a @DJMcMayhem por colocar os comandos ex juntos

:se ve=all|%!wc -L
y$uò/^ *<93>[{};]
xk$pòò/<84> {};][{};]«$
lDî^R0|p

^Ré o caractere literal para <C-r>( 0x12) e <84>é 0x84e <94>é 0x94.

wc -Lfunciona na maioria dos sistemas baseados em * nix, mas não no macOS. Para o macOS, você precisa fazer isso gwc -L depois de obter o coreutils usando o brew, se ainda não o fez.

Experimente online! (Java)

Experimente online! (Python)

Experimente online! (Java novamente)

Isso preserva todas as linhas em branco e não manipula guias, apenas espaços.

Hexdump:

00000000: 3a73 6520 7665 3d61 6c6c 7c25 2177 6320  :se ve=all|%!wc 
00000010: 2d4c 0a79 2475 f22f 5e20 2a93 5b7b 7d3b  -L.y$u./^ *.[{};
00000020: 5d0a 786b 2470 f2f2 2f84 207b 7d3b 5d5b  ].xk$p../. {};][
00000030: 7b7d 3b5d ab24 0a6c 44ee 1230 7c70       {};].$.lD..0|p

Explicação

Primeiro, precisamos poder mover o cursor em qualquer lugar do buffer, então usamos

:se ve=all|...

e encadeamos isso com outro comando ex usando |

Precisamos obter o comprimento da linha mais longa na entrada. Isso pode ser feito com o comando shell wc -L.

       ...|%!wc -L

Isso substitui o buffer atual (contendo a entrada) pelo resultado de wc -L. Dá uma saída de algo como:

            42

e o cursor pousa 4na entrada 42. Em seguida, copiamos esse número usando y$: arrancar o texto da posição do cursor até o final da linha. Isso armazena convenientemente esse número no registro 0. Mas mais sobre isso mais tarde. A entrada é substituída por esse número; portanto, para reverter, precisamos u.

Agora, digamos que a entrada tenha a seguinte aparência:

public class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello, World!");
    }
}

precisamos mover as chaves }do final do buffer para logo após a printlndeclaração.

ò                  " recursively do this until a breaking error:
 /^ *<93>[{};]     "   this compressed regex becomes /^ *\zs[{};]
                   "   this finds any character from `{};` after leading spaces
                   "   the cursor then goes to the `{};`

x                  "   delete character
 k$                "   go to the end of the line above
   p               "   and paste
    ò

Se a regex não puder ser encontrada, ocorrerá um erro de quebra e interromperá a recursão causada por ò .

Agora vem a parte principal deste programa, mova todas as chaves e ponto-e-vírgula e alinhe-as conforme indicado na pergunta.

ò                  " starts recursion
 /<84> {};][{};]«$ "   compressed form of [^ {};][{};]\+$
                   "   finds a sequence of `{};`s at the end of the line with a non-`{};` char to preceding it
 l                 "   move the cursor 1 to the right (since we were on the non-`{};` char now)
  D                "   delete everything from this position to the end of line
                   "   the deleted text contains `{};`
   î               "   execute as normal commands:
    ^R0            "   contains what's in register `0`, ie the length of the longest line
       |           "   now go to the column specified by that number
        p          "   and paste the contents 
                   " implicit ending `ò`

Novamente, essa recursão será interrompida por um erro de quebra causado quando o regex não pôde ser encontrado no buffer.

Edições

  • Usado em Dvez ded$ (nem sei por que perdi isso em primeiro lugar)
  • Comprimido [^(no regex) para<84>
  • Erro corrigido usando \zs(comprimindo-a <93>) e removendo o $em$xk$pò
  • Nova linha inútil removida
  • Regex alterado para tornar o envio compatível com novas regras e ganhou 2 bytes
Kritixi Lithos
fonte
Você poderia salvar um byte se você juntar o seu ex comandos juntos:se ve=all|%!wc -L
DJMcMayhem
@DJMcMayhem Thanks, TIL
Kritixi Lithos
4

Ruby, 100 114 108 bytes

Lê o nome do arquivo como argumento da linha de comando. Se nenhum nome de arquivo for fornecido, ele será lido em STDIN. Não manipula guias.

Experimente online!

f=$<.read.gsub(/[\s;{}]*$/){$&.tr"
 ",''}
$><<f.gsub(/(.*?)([;{}]+)$/){$1.ljust(f.lines.map(&:size).max)+$2}
Value Ink
fonte
Não funciona com esta
Pavel
@ Pavel obrigado por me avisar. Os dois problemas que vi após a inserção no arquivo foram A. uma catchdeclaração recuada e B. um ponto-e-vírgula recuado demais, na linha mais longa do código. Acho que sei exatamente o que preciso para consertar, me dê um segundo. (Além disso, eu atualizei a especificação de mencionar que não pode lidar com abas, e seu arquivo tem guias.)
Valor Ink
Possui abas? Eu apenas encontrei e substituí-lo, e ele fez 0 alterações.
Pavel
3

Perl , 90 bytes

88 bytes de código + -p0sinalizadores.

\@a[y///c]for/.*/g;s/(.*?)\K[{};]$/$"x(@a-$1=~y%%%c).$&/gme;1while s/ *
 *([{};]+)$/$1/m

Experimente online!

Explicações breves:
\@a[y///c]for/.*/g; conta o comprimento da linha mais longa: para cada linha, define o elemento no índice y///c(ou seja, o tamanho da linha) da matriz @a. No final, o índice máximo de @a(ou seja, o tamanho de @a) é o tamanho da linha mais longa.
s/(.*?)\K[{};]$/$"x(@a-$1=~y%%%c).$&/gmecoloca os {};caracteres no final das linhas.
1while s/ *\n *([{};]+)$/$1/mfaz faz com que as chaves nas linhas vazias sigam a linha acima.

Graças ao @primo, de quem "roubei" parcialmente o início do meu código daqui para contar o comprimento da linha mais longa.

dada
fonte
Os aparelhos devem voltar à linha acima, se houver apenas espaço em branco à sua frente, esta resposta não faz isso
Kritixi Lithos
@KritixiLithos, de fato, parecia bom antes que o desafio fosse reformulado (pelo que entendi dos desafios e dos comentários). De qualquer forma, está corrigido agora (eu já tinha o código escrito na minha resposta caso você não percebesse).
Dada
1

Python 2: 228 bytes

import re
g=re.search
def b(a):
    s,l="",a.split('\n')
    r=max([len(k)for k in l]) 
    for k in l:
        n,m=g('[;}{]',k),g('[\w]',k)
        if n:n=n.start()
        if m:m=m.start()
        if n>m and m!=None:s+="\n"+k[:n]+" "*(r-n)
        s+=k[n:]
    print s
Chris H
fonte
Horrivelmente longo. Eu provavelmente deveria ter começado do zero quando percebi que só era ;{}necessário ir no final das linhas anteriores.
21717 Chris H das
1

empilhados , 133 bytes

'\s+([;{}])' '$1'repl lines{!n'[\s;{}]+$'match''join:n\'$'+del\,}"!tr:$size"!$MAXmap@k{e i:e[' 'k i#rpad]"!}map tr[' 'join]map'
'join

Experimente online! Eu poderia estar pensando demais nisso ... mas o que quer. Vou olhar novamente amanhã. Algumas dicas legais:

  1. "!geralmente pode ser usado no lugar de map, salvando um byte ou dois, dependendo se o próximo token começar com uma palavra. No entanto, ele só pode ser usado quando cada átomo da matriz deseja ser mapeado. É semelhante a um mapa profundo.
  2. Um espaço não é necessário após uma função entre aspas, portanto $MAXmapé equivalente a $MAX map, que por sua vez é equivalente a [MAX] map. (Mapeia cada matriz para seu elemento máximo.)
Conor O'Brien
fonte
1

JavaScript (Proposta da ES), 139 121 bytes

f=
s=>s.replace(/^(.*?)\s*(([;{}]\s*)+)$/gm,(_,t,u)=>t.padEnd(Math.max(...s.split`
`.map(s=>s.length)))+u.replace(/\s/g,``))
<textarea rows=10 cols=40 oninput=o.textContent=f(this.value)></textarea><pre id=o>

Requer o Firefox 48 / Chrome 57 / Opera 44 / Safari 10 / Edge 15 para padEnd. Editar: salvou 18 bytes graças a @ValueInk.

Neil
fonte
Você realmente precisa executar s.replace(r,`$1`)ao calcular o comprimento da linha? Qualquer quantidade razoável de preenchimento correto deve ser suficiente; portanto, a contagem do comprimento da linha com ponto e vírgula e colchetes deve ser boa.
Value Ink
0

PHP, 201 194 185 172 167 bytes

foreach($f=file(f)as$s)$x=max($x,strlen($a[]=rtrim($s,"{} ;
")));foreach($a as$i=>$c)echo str_pad($c,""<$c|!$i?$x:0),trim(substr($f[$i],strlen($c))),"
"[""==$a[$i+1]];

recebe entrada do arquivo f; assume quebras de linha de byte único e sem guias; preserva linhas em branco.

  • +2 bytes para delimitar espaço em branco: acrescente +1ao segundo str_padparâmetro.
  • -6 bytes, se foi garantido que nenhuma linha de código consiste em uma única 0:
    remova ""<e substitua ""==por !.

demolir

foreach($f=file(f)as$s)             // loop through file
    $x=max($x,strlen(                   // 3. set $x to maximum code length
        $a[]=                           // 2. append to array $a
            rtrim($s,"{} ;\n")          // 1. strip trailing whitespace and braces
    ));
foreach($a as$i=>$c)echo            // loop through $a
    str_pad($c,                         // 1. print code:
        !$i|""<$c                       // if first line or not empty
        ?$x                             // then padded to length $x
        :0                              // else unpadded (= print nothing)
    ),
    trim(substr($f[$i],strlen($c))),    // 2. print braces
    "\n"[""==$a[$i+1]]                  // 3. if next line has code, print newline
;
Titus
fonte
Tem certeza de que precisa escapar do {}aparelho no regex?
Kritixi Lithos
@KritixiLithos Provavelmente não; mas encontrei uma abordagem mais curta de qualquer maneira.
Titus
0

Java 8, 312 305 bytes

s->{String t="([;{}]+)",z[],r="",a;s=s.replaceAll(t+"[\\s\\n]*","$1").replaceAll(t,"$1\n");int m=0,l;for(String q:s.split("\n"))m=m>(l=q.length())?m:l;for(String q:s.split("\n")){z=q.split("((?<="+t+")|(?="+t+"))",2);for(a="",l=0;l++<m-z[0].length();a+=" ");r+=z[0]+a+(z.length>1?z[1]:"")+"\n";}return r;}

Explicação:

Experimente aqui.

s->{                                  // Method with String parameter and String return-type
  String t="([;{}]+)",                //  Temp regex-String we use multiple times
    z[],a,                            //  Temp String-array and temp String
    r="";                             //  Result-String
  s=s.replaceAll(t+"[\\s\\n]*","$1")  //  We replace all ;{} in the input with zero or more whitespaces/newlines to just ;{}
     .replaceAll(t,"$1\n");           //  and then add a single newline after each group of ;{}
  int m=0,l;                          //  Two temp integers
  for(String q:s.split("\n"))         //  Loop (1) over the lines
    m=m>(l=q.length())?m:l;           //   To determine the longest line
                                      //  End of loop (1)
  for(String q:s.split("\n")){        //  Loop (2) over the lines again
    z=q.split("((?<="+t+")|(?="+t+"))",2);
                                      //   Split on groups of ;{}, but keep them in the array
    for(a="",l=0;l++<m-z[0].length();a+=" "); 
                                      //   Amount of spaces we should add
    r+=z[0]+a+(z.length>1?z[1]:"")+"\n"; 
                                      //   Append this line to the result-String
  }                                   //  End of loop (2)
  return r;                           //  Return the result-String
}                                     // End of method
Kevin Cruijssen
fonte
Estou comentando esta resposta, mas ela se aplica a muitos outros. Atualmente, exigimos que os parâmetros lambda tenham tipos em Java .
Nathan Merrill
1
@ NathanMerrill Temia que o dia do julgamento chegasse. Jk, vou adicioná-lo a partir de agora e eu editei minha resposta, obrigado. ;)
Kevin Cruijssen