Convert braces to Right Hand Brace (Sad Brace)

Right hand brace is a style of code bracketing in which curly braces and semicolons are all aligned to a single point on the right side of a a file.

Generally, this is considered bad practice, for several reasons.

The Challenge

Take a multiline string through any method, and convert it's brace style to Right Hand Brace.

For this challenge, you only need it to work on Java code, however, it should theoretically work on any code that uses Braces and Semicolons.

You must grab all {}; characters in a row, with any amount of whitespace between them. EG. }}, ; } }\n\t\t}, and line them up on the right side of the file through the use of whitespace.

for example:

a {
b;
{c


should become

a {
b ;{
c


Or, more abstractly, push any and all whitespace from the left of all {}; characters, to the right.

Indentation of lines should be otherwise preserved. Lines only containing whitespace after the movement of the {}; characters may optionally be removed.

For example:

a{
b{
c;
}
}
d;


May become either

a        {
b    {
c;}}
d        ;


or

a        {
b    {
c;}}

d        ;


Pushed to the right refers to all the {}; characters being aligned to a point no shorter than the longest line. Any amount of space after that is acceptable.

So all the below is acceptable:

a {
bc;

a  {
bc ;

a   {
bc  ;


etc...

Lines in any code may contain {}; characters between other non-whitspace characters, the handling of this case isn't necessary, although if you're inclined, you should leave them in place. Lines may also not contain any {}; characters at all, and this should be handled correctly. As is shown below.

a {
b ;
c
d }


Because we don't want Code Review to see the horrible things we're doing, you need to make your code as small as possible.

Examples / Testcases

Generic Java

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


becomes...

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


The image itself

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


becomes...

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


Not so Perfectly Generic Python

For contrast

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

Main();


becomes...

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


Edit Notes

I reworded the challenge details, Hopefully I didn't break anyone's view of the rules, I assure you it was unintentional. This should be a much more clear and less self-conflicting spec.

• What's the verdict on lines with multiple semicolons? Something like int a=0;System.out.println(a); – Value Ink Feb 14 '17 at 1:26
• That might no be the best image for the challenge if we don't need to handle for loops like in the sample image? – Dennis Feb 14 '17 at 4:56
• Looks like the image in the question came from this example, which was followed up by this followup, which has more complex examples – Ray Toal Feb 14 '17 at 5:43
• It could be made clearer that you want the ;{} characters gathered up if they're on separate lines (it's only clear from the example, not the rules, and in fact if a line consists of \t} preserving the indentation would mean not moving } up to the end of the previous line) – Chris H Feb 14 '17 at 10:44
• Good god, please tell me nobody actually does this in practice for a verbose language like Java ._. – Magic Octopus Urn Feb 15 '17 at 17:16

V + Bash utilities, 64626160 62 bytes

1 byte saved thanks to @DJMcMayhem for putting the ex commands together

:se ve=all|%!wc -L
y$uò/^ *<93>[{};] xk$pòò/<84> {};][{};]«$lDî^R0|p  ^R is the character literal for <C-r> (0x12) and <84> is 0x84 and <94> is 0x94. wc -L works on most *nix based systems, but not macOS. For macOS, you have to do gwc -L after getting coreutils using brew, if you haven't already. Try it online! (Java) Try it online! (Python) Try it online! (Java again) This preserves all blank lines and does not handle tabs, only spaces. 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


Explanation

First we need to be able to move the cursor anywhere in the buffer, so we use

:se ve=all|...


and we chain this with another ex command using |

We need to get the length of the longest line in the input. This can be done with the shell command wc -L.

       ...|%!wc -L


This overwrites the current buffer (containing the input) with the result of wc -L. It gives an output of something like:

            42


and the cursor lands on the 4 in 42. Then we copy this number by using y$: yank text from the cursor's position to the end of the line. This conveniently stores this number in register 0. But more on that later. The input is replaced with this number, so to revert back, we undo. Now say the input looked somewhat like this: public class HelloWorld{ public static void main(String[] args){ System.out.println("Hello, World!"); } }  we need to move the braces } from the end of the buffer to just after the println statement. ò " 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
ò


If the regex cannot be found, a breaking error happens and breaks out of the recursion caused by ò.

Now comes the main part of this program, move all braces and semi-colons and align them as stated in the question.

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


Again, this recursion will be stopped by a breaking error caused when the regex could not be found in the buffer.

Edits

• Used D instead of d$ (I don't even know why I missed that in the first place) • Compressed [^ (in the regex) to <84> • Fixed bug by using \zs (compressing it into <93>) and by removing the $ in $xk$pò
• Removed useless newline
• Changed regex to make submission compliant with new rules and gained 2 bytes
• You could save one byte if you join your ex commands together :se ve=all|%!wc -L – DJMcMayhem Feb 14 '17 at 19:03
• @DJMcMayhem Thanks, TIL – Cows quack Feb 14 '17 at 19:27

Ruby, 100114 108 bytes

Reads file name as command line argument. If no file name is supplied, it'll read from STDIN. Does not handle tabs.

Try it online!

f=$<.read.gsub(/[\s;{}]*$/){$&.tr" ",''}$><<f.gsub(/(.*?)([;{}]+)$/){$1.ljust(f.lines.map(&:size).max)+$2}  • I can't get it to work, can you help me out? – Pavel Feb 14 '17 at 2:55 • @Pavel try this on for size. – Value Ink Feb 14 '17 at 3:01 • Doesn't work with this – Pavel Feb 14 '17 at 3:07 • @Pavel thanks for letting me know. The two issues I saw after piping into file were A. an indented catch statement, and B. a semicolon that was indented way too much, on the longest line in the code. I think I know just the thing I need to fix it, give me a sec. (Also, I updated the spec to mention it can't handle tabs, and your file has tabs.) – Value Ink Feb 14 '17 at 3:16 • Does it have tabs? I just did a find and replace on it, and it made 0 changes. – Pavel Feb 14 '17 at 3:25 Perl, 90 bytes 88 bytes of code + -p0 flags. \@a[y///c]for/.*/g;s/(.*?)\K[{};]$/$"x(@a-$1=~y%%%c).$&/gme;1while s/ * *([{};]+)$/$1/m  Try it online! Short explanations: \@a[y///c]for/.*/g; counts the length of the longest line: for each line, it defines the element at index y///c (ie the size of the line) of the array @a. At the end, the max index of @a (ie. the size of @a) is the size of the longest line. s/(.*?)\K[{};]$/$"x(@a-$1=~y%%%c).$&/gme places the {}; characters at the end of the lines. 1while s/ *\n *([{};]+)$/$1/m makes makes the braces on empty lines go on the line above. Thanks to @primo from whom I partially "stole" the beginning of my code from here to count the length of the longest line. • The braces must go back up to the line above if there is only whitespace before them, this answer doesn't do that – Cows quack Feb 15 '17 at 10:26 • @KritixiLithos indeed, it seemed fine before the challenge was reworded (from what I understood from both the challenges and the comments). Anyway, it's fixed now (I already had the code written in my answer in case you didn't notice). – Dada Feb 15 '17 at 10:38 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  • Horribly long. I probably should have started from scratch when I realised lone ;{}s needed to go on the end of the previous lines. – Chris H Feb 14 '17 at 12:07 stacked, 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


Try it online!I could be heavily overthinking this... but whatevs. I'll look at it again tomorrow. Some nice tips:

1. "! can often be used in place of map, saving a byte or two, depending on if the next token starts with a word. However, it can only be used when each atom of the array is wanting to be mapped over. It's similar to a deep map.
2. A space is not needed after a quoted function, so $MAXmap is equivalent to $MAX map, which in turn is equivalent to [MAX] map. (Maps each array to its maximal element.)

JavaScript (ES Proposal), 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> Requires Firefox 48/Chrome 57/Opera 44/Safari 10/Edge 15 for padEnd. Edit: Saved 18 bytes thanks to @ValueInk. • Do you really need to run s.replace(r,$1) when calculating the line length? Any amount of reasonable right-padding should be enough, so counting line length with the semicolons and brackets should be fine. – Value Ink Feb 17 '17 at 4:20

PHP, 201194185172 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]];


takes input from file f; assumes single byte linebreaks and no tabs; preserves blank lines.

• +2 bytes for delimiting whitespace: append +1 to the second str_pad parameter.
• -6 bytes if it was guaranteed that no code line consists of a single 0:
Remove ""< and replace ""== with !.

breakdown

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
;

• Are you sure you need to escape the {} braces in the regex? – Cows quack Feb 14 '17 at 12:44
• @KritixiLithos Probably not; but I found a shorter approach anyway. – Titus Feb 14 '17 at 12:47

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


Explanation:

Try it here.

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