Konwertuj nawiasy klamrowe na prawą nawias klamrowy (Smutny nawias klamrowy)


26

Nawiasy klamrowe to styl nawiasowania kodu, w którym nawiasy klamrowe i średniki są wyrównane do jednego punktu po prawej stronie pliku.

Przykładowy obraz tutaj

Z wielu powodów uważa się to za złą praktykę.

Wyzwanie

Weź ciąg multilinii dowolną metodą i przekonwertuj jego styl nawiasów klamrowych na prawą nawias klamrowy.

W przypadku tego wyzwania potrzebujesz go tylko do pracy z kodem Java, jednak teoretycznie powinien on działać z każdym kodem, który używa nawiasów klamrowych i średników.

Musisz złapać wszystkie {};postacie z rzędu, z dowolną spacją między nimi. NA PRZYKŁAD. }}, ; } }\n\t\t}i wyrównaj je po prawej stronie pliku za pomocą białych znaków.

na przykład:

a {
b;
{c

powinno stać się

a {
b ;{
c

Lub, bardziej abstrakcyjnie, przesuń dowolną spację od lewej strony wszystkich {};znaków w prawo.

Wcięcie linii powinno być w inny sposób zachowane. Linie zawierające tylko białe znaki po ruchu {};znaków mogą być opcjonalnie usunięte.

Na przykład:

a{
    b{
        c;
    }
}
d;

Może stać się albo

a        {
    b    {
        c;}}
d        ;

lub

a        {
    b    {
        c;}}


d        ;

Przesunięcie w prawo oznacza {};wyrównanie wszystkich znaków do punktu nie krótszego niż najdłuższa linia. Każda ilość miejsca po tym jest akceptowalna.

Tak więc wszystkie poniższe elementy są dopuszczalne:

a {
bc;

a  {
bc ;

a   {
bc  ;

itp...

Linie w dowolnym kodzie mogą zawierać {};znaki między innymi znakami spacjami, obsługa tego przypadku nie jest konieczna, chociaż jeśli masz skłonność, powinieneś pozostawić je na miejscu. Linie mogą także w ogóle nie zawierać żadnych {};znaków i należy z tym poprawnie postępować. Jak pokazano poniżej.

a {
b ;
c
d }

Ponieważ nie chcemy, aby Code Review widział straszne rzeczy, które robimy, musisz zminimalizować swój kod.

Przykłady / przypadki testowe

Ogólna Java

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

staje się...

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

Sam obraz

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

staje się...

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

Nie tak idealnie ogólny Python

Dla kontrastu

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

Main();

staje się...

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

Uwagi

  • Standardowe Luki zastosowanie
  • Obowiązuje standardowe IO
  • To jest , więc wygrywa najkrótszy program w bajtach!
  • Nie jestem odpowiedzialny za szkody związane z programowaniem w stylu prawej ręki
  • Baw się dobrze!

Edytuj notatki

Przeredagowałem szczegóły wyzwania. Mam nadzieję, że nie złamałem niczyjego spojrzenia na zasady, zapewniam cię, że było to niezamierzone. To powinno być znacznie bardziej jasne i mniej sprzeczne ze specyfikacją.


Jaki jest werdykt dla linii z wieloma średnikami? Coś w styluint a=0;System.out.println(a);
Value Ink

2
To może nie być najlepszy obraz do wyzwania, jeśli nie musimy obsługiwać pętli jak na przykładowym obrazie?
Dennis

1
Wygląda na to, że obraz w pytaniu pochodzi z tego przykładu , po którym nastąpiła ta kontynuacja , która zawiera bardziej złożone przykłady
Ray Toal

2
Można by ;{}wyjaśnić , że chcesz zebrać postacie, jeśli znajdują się w osobnych wierszach (wynika to tylko z przykładu, a nie z reguł, a w rzeczywistości, jeśli linia polega na \t}zachowaniu wcięcia, oznacza to, że nie przesunie }się do końca poprzedniej linii)
Chris H

2
Dobry Boże, proszę powiedz mi, że nikt tak naprawdę nie robi tego w pełnym języku, takim jak Java ._.
Magic Octopus Urn

Odpowiedzi:


5

Narzędzia V + Bash, 64 62 61 60 62 bajtów

1 bajt zapisany dzięki @DJMcMayhem za połączenie poleceń ex razem

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

^Rjest literałowym znakiem dla <C-r>( 0x12) oraz <84>jest 0x84i <94>jest 0x94.

wc -Ldziała na większości systemów opartych na * nix, ale nie na macOS. W przypadku systemu macOS musisz zrobić gwc -L po uzyskaniu coreutils za pomocą naparu, jeśli jeszcze tego nie zrobiłeś.

Wypróbuj online! (Jawa)

Wypróbuj online! (Pyton)

Wypróbuj online! (Znowu Java)

To zachowuje wszystkie puste linie i nie obsługuje tabulatorów, tylko spacje.

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

Wyjaśnienie

Najpierw musimy umieć przesuwać kursor w dowolne miejsce w buforze, więc używamy

:se ve=all|...

i łączymy to za pomocą innego polecenia ex przy użyciu |

Musimy uzyskać długość najdłuższej linii na wejściu. Można to zrobić za pomocą polecenia powłoki wc -L.

       ...|%!wc -L

To zastępuje bieżący bufor (zawierający dane wejściowe) wynikiem wc -L. Daje to wynik czegoś takiego jak:

            42

a kursor ląduje na 4IN 42. Następnie kopiujemy ten numer, używając y$: szarpnij tekst od pozycji kursora do końca linii. To wygodnie przechowuje ten numer w rejestrze 0. Ale o tym później. Dane wejściowe są zastępowane tą liczbą, więc aby wrócić, nie umusimy.

Powiedzmy teraz, że dane wejściowe wyglądały mniej więcej tak:

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

musimy przenieść nawiasy klamrowe }z końca bufora do tuż po printlninstrukcji.

ò                  " 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
    ò

Jeśli nie można znaleźć wyrażenia regularnego, pojawia się błąd przełamania i wypływa on z rekurencji spowodowanej przez ò.

Teraz pojawia się główna część tego programu, przesuń wszystkie nawiasy klamrowe i średniki i wyrównaj je, jak podano w pytaniu.

ò                  " 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 `ò`

Ponownie rekursja zostanie zatrzymana przez błąd zerwania spowodowany, gdy nie można znaleźć wyrażenia regularnego w buforze.

Edycje

  • Używane Dzamiast d$(nawet nie wiem, dlaczego mi tego brakowało)
  • Skompresowane [^(w wyrażeniu regularnym) do<84>
  • Poprawiono błąd przy użyciu \zs(prasowanie jej <93>) i usuwając $in$xk$pò
  • Usunięto bezużyteczną nową linię
  • Zmieniono wyrażenie regularne, aby przesyłanie było zgodne z nowymi zasadami, i zyskałem 2 bajty

Możesz zapisać jeden bajt, jeśli dołączysz do swoich byłych poleceń razem:se ve=all|%!wc -L
DJMcMayhem

@DJMcMayhem Dzięki, TIL
Kritixi Lithos

4

Rubinowy, 100 114 108 bajtów

Odczytuje nazwę pliku jako argument wiersza poleceń. Jeśli nazwa pliku nie zostanie podana, zostanie odczytany ze STDIN. Nie obsługuje kart.

Wypróbuj online!

f=$<.read.gsub(/[\s;{}]*$/){$&.tr"
 ",''}
$><<f.gsub(/(.*?)([;{}]+)$/){$1.ljust(f.lines.map(&:size).max)+$2}



Nie działa z tym
Pavel

@Pavel dzięki za poinformowanie mnie. Dwa problemy, które zobaczyłem po włożeniu do pliku, to: A. wcięcie catch, a B. średnik, który został wcięty zdecydowanie za dużo, w najdłuższym wierszu kodu. Myślę, że wiem, co muszę naprawić, daj mi chwilę. (Również zaktualizowałem specyfikację, aby wspomnieć, że nie obsługuje kart, a twój plik ma karty.)
Wartość tuszu

Czy to ma zakładki? Właśnie znalazłem i zastąpiłem go i wprowadziłem 0 zmian.
Pavel

3

Perl , 90 bajtów

88 bajtów kodu + -p0flagi.

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

Wypróbuj online!

Krótkie wyjaśnienia:
\@a[y///c]for/.*/g; zlicza długość najdłuższej linii: dla każdej linii definiuje element na indeksie y///c(tj. Rozmiar linii) tablicy @a. Na koniec maksymalny indeks @a(tj. Rozmiar @a) to rozmiar najdłuższej linii.
s/(.*?)\K[{};]$/$"x(@a-$1=~y%%%c).$&/gmeumieszcza {};znaki na końcu linii.
1while s/ *\n *([{};]+)$/$1/msprawia, że ​​nawiasy klamrowe na pustych liniach przechodzą na linię powyżej.

Dzięki @primo, od którego częściowo „ukradłem” początek mojego kodu , aby policzyć długość najdłuższej linii.


Nawiasy klamrowe muszą wrócić do powyższej linii, jeśli przed nimi jest tylko
biała

@KritixiLithos rzeczywiście wydawało się dobrze, zanim wyzwanie zostało przeredagowane (z tego, co zrozumiałem zarówno z wyzwań, jak i komentarzy). W każdym razie jest już naprawione (miałem już kod napisany w odpowiedzi na wypadek, gdybyś nie zauważył).
Dada

1

Python 2: 228 bajtów

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

Okropnie długo. Prawdopodobnie powinienem zacząć od zera, kiedy zdałem sobie sprawę, że samotni ;{}muszą iść na koniec poprzednich linii.
Chris H

1

ułożone , 133 bajty

'\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

Wypróbuj online! Mógłbym mocno to przemyśleć ... ale co. Spojrzę na to jutro. Kilka fajnych wskazówek:

  1. "!może być często używany zamiast map, oszczędzając bajt lub dwa, w zależności od tego, czy następny token zaczyna się od słowa. Można go jednak użyć tylko wtedy, gdy każdy atom tablicy chce zostać zamapowany. Jest podobny do głębokiej mapy.
  2. Po funkcji cytowanej spacja nie jest potrzebna, więc $MAXmapjest równoważna z $MAX map, co z kolei jest równoważne z [MAX] map. (Mapuje każdą tablicę do jej maksymalnego elementu.)

1

JavaScript (propozycja ES), 139 121 bajtów

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>

Wymaga przeglądarki Firefox 48 / Chrome 57 / Opera 44 / Safari 10 / Edge 15 dla padEnd. Edycja: Zapisano 18 bajtów dzięki @ValueInk.


Czy naprawdę musisz biegać s.replace(r,`$1`)podczas obliczania długości linii? Każda wystarczająca ilość prawego dopełnienia powinna wystarczyć, więc liczenie długości linii za pomocą średników i nawiasów powinno być w porządku.
Wartość tuszu

0

PHP, 201 194 185 172 167 bajtów

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]];

pobiera dane wejściowe z pliku f; zakłada podział bajtów na jeden bajt i brak tabulatorów; zachowuje puste linie.

  • +2 bajty do rozgraniczenia białych znaków: dołącz +1do drugiego str_padparametru.
  • -6 bajtów, jeśli zostało zagwarantowane, że żadna linia Kod składa się z pojedynczej 0:
    Usunąć ""<i wymienić ""==z !.

awaria

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
;

Czy na pewno musisz uciec od {}nawiasów klamrowych w wyrażeniu regularnym?
Kritixi Lithos

@KritixiLithos Prawdopodobnie nie; ale i tak znalazłem krótsze podejście.
Tytus

0

Java 8, 312 305 bajtów

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

Wyjaśnienie:

Wypróbuj tutaj.

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

Hej, komentuję tę odpowiedź, ale dotyczy ona wielu innych. Obecnie wymagamy parametrów lambda, aby mieć typy w Javie .
Nathan Merrill,

1
@NathanMerrill Bał się, że nadejdzie dzień sądu. Jk, dodam ją od teraz i zredagowałem swoją odpowiedź, dzięki. ;)
Kevin Cruijssen
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.