Convert braces to Right Hand Brace (Sad Brace)

V + Bash utilities, 64 62 61 60 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

Ruby, 100 114 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}

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.