Перетворення брекетів в правильну підтяжку (Sad Brace)


26

Праворучний брекет - це стиль дужки з кодом, у якому фігурні дужки та крапки з комою вирівнюються до однієї точки праворуч файлу aa.

Приклад зображення перейдіть сюди

Як правило, це вважається поганою практикою з кількох причин.

Змагання

Візьміть рядок багаторядкових будь-яким методом і перетворіть його стиль дужки в правильну руку.

Для цього завдання вам потрібно лише працювати над кодом Java, проте теоретично він повинен працювати над будь-яким кодом, який використовує дужки та крапки з комою.

Ви повинні захопити всіх {};символів підряд, з будь-якою кількістю пробілів між ними. EG. }}, ; } }\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 }

Оскільки ми не хочемо, щоб у перегляді коду бачили жахливі речі, які ми робимо, вам потрібно зробити свій код якомога меншим.

Приклади / Тести

Загальна 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                                 ;}}

Не такий ідеально родовий пітон

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

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

Main();

стає ...

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

Примітки

  • Застосовуються стандартні лазівки
  • Застосовується стандартний IO
  • Це , тому найкоротша програма в байтах виграє!
  • Я не несу відповідальності за збитки, пов’язані з програмуванням у стилі Brace Right Hand
  • Веселіться!

Редагувати нотатки

Я переформулював деталі виклику. Сподіваюся, я не порушив уявлення когось про правила, запевняю, це було ненавмисно. Це має бути набагато більш чіткою і менш конфліктною специфікацією.


Який вердикт у рядках з кількома крапками з комою? Щось на кшталтint a=0;System.out.println(a);
Ink Value

2
Це може бути не найкращим зображенням для виклику, якщо нам не потрібно обробляти петлі, як у зразковому зображенні?
Денніс

1
Схоже, образ у питанні з’явився з цього прикладу , за яким слідував цей подальший
опис

2
Можливо, буде зрозуміліше, що ви хочете, щоб ;{}символи збиралися, якщо вони знаходяться в окремих рядках (це зрозуміло лише з прикладу, а не правил. Насправді, якщо рядок складається з \t}збереження відступу, це означає, що не рухається }до кінця попереднього рядка)
Кріс Х

2
Боже мій, скажіть, будь ласка, ніхто насправді не робить цього на практиці для такої багатослівної мови, як Java ._
Magic Octopus Urn

Відповіді:


5

V + Bash утиліти, 64 62 61 60 62 байт

1 байт збережено завдяки @DJMcMayhem за з'єднання колишніх команд

: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 за допомогою варіння, якщо ви ще цього не зробили.

Спробуйте в Інтернеті! (Java)

Спробуйте в Інтернеті! (Пітон)

Спробуйте в Інтернеті! (Знову Java)

Це зберігає всі порожні рядки і не обробляє вкладки, а лише пробіли.

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 |

Нам потрібно отримати довжину найдовшого рядка на вході. Це можна зробити за допомогою команди shell 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 байти

Ви можете зберегти один байт, якщо разом приєднаєтесь до своїх колишніх команд: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 дякую, що повідомили мені. Дві проблеми, які я бачив після прошивки у файл, були A. з відступом catch, а B. крапкою з комою, яка була занадто сильно відрезаною, на найдовшому рядку в коді. Я думаю, що я знаю лише те, що мені потрібно виправити, дайте мені секунду. (Також я оновив специфікацію, щоб згадати, що вона не може працювати з вкладками, а у вашому файлі є вкладки.)
Значення чорнила

Чи є вкладки? Я просто знайшов і замінив його, і він зробив 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. Зрештою, індекс max @a(тобто розмір @a) - це розмір найдовшої лінії.
s/(.*?)\K[{};]$/$"x(@a-$1=~y%%%c).$&/gmeрозміщує {};символів у кінці рядків.
1while s/ *\n *([{};]+)$/$1/mзмушує дужки на порожніх рядках йти по лінії вище.

Завдяки @primo, від якого я частково "вкрав" початок свого коду звідси, щоб порахувати довжину найдовшого рядка.


Дужки повинні повернутися до
верхньої

@KritixiLithos справді здавалося прекрасним, перш ніж виклик було перероблено (з того, що я зрозумів і з викликів, і з коментарів). У будь-якому випадку це виправлено зараз (я вже писав код у своїй відповіді, якщо ви цього не помітили).
Дада

1

Пітон 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

Спробуйте в Інтернеті! Я міг би сильно переосмислити це ... але Whatevs. Я завтра знову погляну на це. Кілька приємних порад:

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

Ви впевнені, що вам потрібно уникнути {}дужок у регексе?
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, додамо його відтепер, і я відредагував свою відповідь, дякую. ;)
Кевін Круїссен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.