Преобразовать скобки в правую скобку (Sad Brace)

26

Правая скобка - это стиль брекетинга кода, при котором фигурные скобки и точки с запятой выровнены по одной точке на правой стороне файла.

Пример изображения здесь

Как правило, это считается плохой практикой по нескольким причинам.

Соревнование

Возьмите многострочную строку с помощью любого метода и преобразуйте ее стиль скобок в правую скобку.

Для этой задачи вам нужно, чтобы он работал только с кодом Java, однако теоретически он должен работать с любым кодом, который использует фигурные скобки и точки с запятой.

Вы должны захватить все {};символы подряд с любым количеством пробелов между ними. НАПРИМЕР. }}, ; } }\n\t\t}И выстроить их на правой стороне файла через использование пробелов.

например:

a {
b;
{c

должен стать

a {
b ;{
c

Или, если говорить более абстрактно, сдвиньте все пробелы слева от всех {};символов вправо.

Отступы строк должны быть сохранены в противном случае. Строки, содержащие только пробелы после перемещения {};символов, могут быть удалены.

Например:

a{
    b{
        c;
    }
}
d;

Может стать либо

a        {
    b    {
        c;}}
d        ;

или

a        {
    b    {
        c;}}


d        ;

Выдвинутый вправо относится ко всем {};символам, выравниваемым по точке, не короче самой длинной линии. Любое количество места после этого приемлемо.

Так что все нижеприведенное приемлемо:

a {
bc;

a  {
bc ;

a   {
bc  ;

так далее...

Строки в любом коде могут содержать {};символы между другими непробельными символами, обработка этого случая не требуется, хотя, если вы склонны, вы должны оставить их на месте. Строки могут также вообще не содержать {};символов, и это должно быть обработано правильно. Как показано ниже.

a {
b ;
c
d }

Поскольку мы не хотим, чтобы Code Review видел ужасные вещи, которые мы делаем, вы должны сделать свой код как можно меньше.

Примеры / Тестовые случаи

Универсальная Java

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

становится ...

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

Само изображение

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

становится ...

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

Для контраста

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

Main();

становится ...

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

Заметки

  • Стандартные лазейки применяются
  • Стандартное IO применяется
  • Это , поэтому выигрывает самая короткая программа в байтах!
  • Я не несу ответственности за ущерб, связанный с программированием в стиле Right Hand Brace
  • Повеселись!

Редактировать заметки

Я перефразировал детали соревнования. Надеюсь, я не нарушил чью-то точку зрения на правила, уверяю вас, это было непреднамеренно. Это должно быть гораздо более ясным и менее противоречивым.

Ataco
источник
Какой вердикт в строках с несколькими точками с запятой? Нечто подобноеint a=0;System.out.println(a);
Value Ink
2
Может быть, это не лучшее изображение для испытания, если нам не нужно обрабатывать циклы, как в образце?
Деннис
1
Похоже, что изображение в вопросе пришло из этого примера , за которым последовало это продолжение , в котором есть более сложные примеры
Рэй
2
Можно было бы прояснить, что вы хотите, чтобы ;{}символы собирались, если они находятся на отдельных строках (это видно только из примера, а не из правил, и на самом деле, если строка состоит из \t}сохранения отступа, это означало бы не двигаться }до конца). предыдущей строки)
Chris H
2
Боже мой, пожалуйста, скажите мне, что на самом деле никто не делает этого на практике для многословного языка, такого как Java ._.
Волшебная урна осьминога

Ответы:

5

Утилиты V + Bash, 64 62 61 60 62 байта

1 байт сохранен благодаря @DJMcMayhem за соединение ex-команд

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

^Rсимвольный литерал для <C-r>( 0x12) и <84>есть 0x84и <94>есть 0x94.

wc -Lработает на большинстве систем * nix, но не на macOS. Для macOS вы должны сделать это gwc -L после получения coreutils, используя brew, если вы этого еще не сделали.

Попробуйте онлайн! (Джава)

Попробуйте онлайн! (Python)

Попробуйте онлайн! (Опять ява)

Это сохраняет все пустые строки и не обрабатывает вкладки, только пробелы.

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

объяснение

Сначала мы должны иметь возможность переместить курсор в любое место в буфере, поэтому мы используем

:se ve=all|...

и мы связываем это с другой командой ex, используя |

Нам нужно получить длину самой длинной строки на входе. Это можно сделать с помощью команды оболочки wc -L.

       ...|%!wc -L

Это перезаписывает текущий буфер (содержащий входные данные) с результатом wc -L. Это дает что-то вроде:

            42

и курсор попадает на 4ин 42. Затем мы копируем это число с помощью y$: yank текста с позиции курсора до конца строки. Это удобно хранит этот номер в реестре 0. Но об этом чуть позже. Вход заменяется на этот номер, поэтому, чтобы вернуться назад, мы возвращаемся u.

Теперь скажите, что вход выглядел примерно так:

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

нам нужно переместить фигурные скобки }от конца буфера сразу после printlnоператора.

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

Если регулярное выражение не может быть найдено, возникает ошибка прерывания и прерывание рекурсии, вызванное ò.

Теперь перейдем к основной части этой программы, переместите все скобки и точки с запятой и выровняйте их, как указано в вопросе.

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

Опять же, эта рекурсия будет остановлена ​​из-за ошибки прерывания, вызванной невозможностью найти регулярное выражение в буфере.

Правки

  • Используется Dвместо d$(я даже не знаю, почему я пропустил это в первую очередь)
  • Сжатый [^(в регулярном выражении) до<84>
  • Исправлена ошибка при использовании \zs(сжатие его в <93>) и удалением $ин$xk$pò
  • Удален бесполезный перевод строки
  • Изменено регулярное выражение для обеспечения соответствия представления новым правилам и получено 2 байта
Kritixi Lithos
источник
Вы можете сохранить один байт, если присоединитесь к своим бывшим командам вместе:se ve=all|%!wc -L
DJMcMayhem
@DJMcMayhem Спасибо, TIL
Kritixi Lithos
4

Рубин, 100 114 108 байт

Читает имя файла в качестве аргумента командной строки. Если имя файла не указано, оно будет считано из STDIN. Не обрабатывает вкладки.

Попробуйте онлайн!

f=$<.read.gsub(/[\s;{}]*$/){$&.tr"
 ",''}
$><<f.gsub(/(.*?)([;{}]+)$/){$1.ljust(f.lines.map(&:size).max)+$2}
Значение чернил
источник
@Pavel примерь это для размера.
Чернила стоимости
Не работает с этим
Павел
@Pavel, спасибо, что дал мне знать. Две проблемы, которые я увидел после передачи в файл, были: А. catchЗаявление с отступом и Б. Точка с запятой, которая была слишком много отступа, в самой длинной строке кода. Я думаю, я знаю только то, что мне нужно, чтобы это исправить, дай мне секунду. (Также я обновил спецификацию, чтобы упомянуть, что она не может обрабатывать вкладки, а в вашем файле есть вкладки.)
Value Ink
Есть ли вкладки? Я только что нашел и заменил его, и он сделал 0 изменений.
Павел
3

Perl , 90 байт

88 байт кода + -p0флаги.

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

Попробуйте онлайн!

Краткие пояснения:
\@a[y///c]for/.*/g; подсчитывает длину самой длинной строки: для каждой строки он определяет элемент по индексу y///c(то есть по размеру строки) массива @a. В конце, максимальный индекс @a(т.е. размер @a) - это размер самой длинной строки.
s/(.*?)\K[{};]$/$"x(@a-$1=~y%%%c).$&/gmeразмещает {};символы в конце строк.
1while s/ *\n *([{};]+)$/$1/mmake заставляет скобки на пустых строках идти в строке выше.

Благодаря @primo, откуда я частично «украл» начало моего кода отсюда, чтобы посчитать длину самой длинной строки.

папа
источник
Скобки должны вернуться к строке выше, если перед ними только пробел, этот ответ не делает этого
Kritixi Lithos
@KritixiLithos действительно, казалось, что все было хорошо до того, как задача была переформулирована (из того, что я поняла из задач и комментариев). В любом случае, это исправлено (у меня уже был код, написанный в моем ответе на случай, если вы не заметили).
Дада
1

Python 2: 228 байт

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
Крис Х
источник
Ужасно долго Я, наверное, должен был начать с нуля, когда понял, что одиночки ;{}должны идти в конце предыдущих строк.
Крис Х
1

сложено , 133 байта

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

Попробуйте онлайн! Я мог бы сильно обдумать это ... но что угодно. Я посмотрю на это снова завтра. Несколько хороших советов:

  1. "!часто может использоваться вместо mapсохранения одного или двух байтов, в зависимости от того, начинается ли следующий токен со слова. Тем не менее, он может использоваться только тогда, когда каждый атом массива хочет отображаться. Это похоже на глубокую карту.
  2. Пробел после кавычки не требуется, поэтому $MAXmapэквивалентен $MAX map, что, в свою очередь, эквивалентно [MAX] map. (Сопоставляет каждый массив с его максимальным элементом.)
Конор О'Брайен
источник
1

JavaScript (предложение ES), 139 121 байт

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>

Требуется Firefox 48 / Chrome 57 / Opera 44 / Safari 10 / Edge 15 для padEnd. Изменить: Сохранено 18 байт благодаря @ValueInk.

Нил
источник
Вам действительно нужно работать s.replace(r,`$1`)при расчете длины линии? Любого количества разумных правых отступов должно быть достаточно, поэтому подсчет длины строки с помощью точек с запятой и скобок должен быть в порядке.
Чернила стоимости
0

PHP, 201 194 185 172 167 байт

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

принимает данные из файла f; предполагает однобайтовые разрывы строк и отсутствие вкладок; сохраняет пустые строки.

  • +2 байта для разделения пробелов: добавьте +1ко второму str_padпараметру.
  • -6 байт, если было гарантировано, что ни одна строка кода не состоит из одной 0:
    удалить ""<и заменить ""==на !.

сломать

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
источник
Вы уверены, что вам нужно избежать {}скобок в регулярном выражении?
Kritixi Lithos
@KritixiLithos Наверное, нет; но я все равно нашел более короткий подход.
Тит
0

Java 8, 312 305 байт

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

Объяснение:

Попробуй это здесь.

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
Кевин Круйссен
источник
Привет, я комментирую этот ответ, но он относится ко многим другим из ваших. В настоящее время мы требуем, чтобы лямбда-параметры имели типы в Java .
Натан Меррилл
1
@NathanMerrill боялся, что придет день суда. Jk, добавлю его, и я отредактировал свой ответ, спасибо. ;)
Кевин Круйссен