8
\$\begingroup\$

I've got some Java pseudocode that uses whitespace instead of curly braces, and I want you to convert it.

I/O

Your program should take an input file along with a number designating how many spaces are used to indent a block. Here's an example:

$ convert.lang input.p 4
// Convert using 4 spaces as the block delimiter
$ convert.lang input.p 2
// Convert using 2 spaces as the block delimiter

It should then convert the result using the specified block delimiter and output the result to stdout.

The meat of the program

Blocks open with : and each line within the block is indented using the block delimiter, like Python code.

while(true):
    System.out.println("Test");

Each : is replaced with a {, and a } is appended to the end of the block.

while(true) {
    System.out.println("Test");
}

Examples

Input:

public class Test:
    public static void main(String[] args):
        System.out.println("Java is verbose...");

Output:

$ convert Test.pseudojava 4
public class Test {
    public static void main(String[] args) {
        System.out.println("Java is verbose...");
    }
}

Input:

main():
  printf("Hello World");

Output:

$ convert test.file 2
main() {
  printf("Hello World");
}

Input:

def generic_op(the_stack, func):
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list):
        if b:
            return
        top = b.pop(0)
        while b:
            top = func(top, b.pop(0))
        the_stack.push(top)
    else:
        a = the_stack.pop()
        return func(a, b)

Output:

$ convert code.py 4
def generic_op(the_stack, func){
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list) {
        if b {
            return
        }
        top = b.pop(0)
        while b {
            top = func(top, b.pop(0))
        }
        the_stack.push(top)
    }
    else {
        a = the_stack.pop()
        return func(a, b)
    }
}

Scoring

The code with the least amount of bytes wins!

\$\endgroup\$
  • 1
    \$\begingroup\$ Can we assume that the input contains no comments? \$\endgroup\$ – Martin Ender Oct 19 '15 at 7:19
  • 1
    \$\begingroup\$ @MartinBüttner It may contain comments, but the comments won't contain ':'. Basically, yes. \$\endgroup\$ – phase Oct 19 '15 at 7:32
  • 3
    \$\begingroup\$ What about labels, which are the usual reason that a line would end in a colon in valid Java source? \$\endgroup\$ – Peter Taylor Oct 19 '15 at 8:11
  • 1
    \$\begingroup\$ I've never seen a label anywhere but the beginning of a line. \$\endgroup\$ – SuperJedi224 Oct 19 '15 at 13:20
  • 2
    \$\begingroup\$ I've just been reminded of how much I hate Java. \$\endgroup\$ – lirtosiast Nov 16 '15 at 4:46
5
\$\begingroup\$

Perl, 41 bytes

#!perl -p0
1while s/( *).*\K:((
\1 .*)+)/ {\2
\1}/

Counting the shebang as two, input is taken from stdin. A command line argument need not be provided. Any valid nesting context can be determined (and matched) without knowing the indentation size.


Regex Break-Down

( *)                   # as many spaces as possible (\1)
    .*                 # as many non-newline characters as possible \
                         (greediness ensures this will always match a full line)
      \K               # keep all that (i.e. look-behind assertion)
        :              # colon at eol (newline must be matched next)
         (
          (
           \n\1        # newline with at least one more space than the first match
                .*     # non-newlines until eol
                  )+   # as many of these lines as possible
                    )  # grouping (\2)

Sample Usage

in1.dat

public class Test:
    public static void main(String[] args):
        System.out.println("Java is verbose...");

Output

$ perl py2java.pl < in1.dat
public class Test {
    public static void main(String[] args) {
        System.out.println("Java is verbose...");
    }
}

in2.dat

main():
  printf("Hello World");

Output

$ perl py2java.pl < in2.dat
main() {
  printf("Hello World");
}

in3.dat

def generic_op(the_stack, func):
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list):
        if b:
            return
        top = b.pop(0)
        while b:
            top = func(top, b.pop(0))
        the_stack.push(top)
    else:
        a = the_stack.pop()
        return func(a, b)

Output

$ perl py2java.pl < in3.dat
def generic_op(the_stack, func) {
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list) {
        if b {
            return
        }
        top = b.pop(0)
        while b {
            top = func(top, b.pop(0))
        }
        the_stack.push(top)
    }
    else {
        a = the_stack.pop()
        return func(a, b)
    }
}
\$\endgroup\$
  • \$\begingroup\$ i just wrote this in ruby \$\endgroup\$ – Not that Charles Nov 16 '15 at 7:54
2
\$\begingroup\$

Python 3, 299 265 bytes

import sys;s=int(sys.argv[2]);t="";b=0
for l in open(sys.argv[1]):
 h=l;g=0
 for c in l:
  if c!=" ":break
  g+=1
 if g/s<b:h=" "*g+"}\n"+h;b-=1
 if l.strip().endswith(":"):h=l.split(":")[0];h+=" {";b+=1
 t+=h+"\n"
b-=1
while b>-1:
 t+=" "*(b*s)+"}\n"b-=1
print(t)

Boom bam pow.

Algorithm used:

//global vars
string total //total modified program
int b //indent buffer

line thru lines: //iterate over every line
  string mline = "" //line to be added to the total

  //calculate the amount of spaces before the line (could be a lot easier)
  int spaces = 0 //total spaces
  c thru line: //go through every character in the line
    if c != " ": //if the current char isn't a space (meaning we went though all of them
        break //break out of iterating through chars
    spaces++ //increment the spaces because we've hit a space (hurr derr)

  if spaces/SPACE_SETTING < b: //if indent count of the current line is less than the indent buffer
    mline = "}\n" + line //add closing bracket to beginning of line
    b-- //decrement buffer

  if line.endswith(":"): //if the line ends with a `:`
    remove : from line
    mline += " {" //append {
    b++ //increment buffer
  total += mline //add modified line to total

print(total)
\$\endgroup\$
  • \$\begingroup\$ Can you include an explanation? \$\endgroup\$ – TanMath Nov 16 '15 at 5:22
  • \$\begingroup\$ @TanMath Added the algorithm I used \$\endgroup\$ – phase Nov 16 '15 at 5:39
  • \$\begingroup\$ Does it work with Python 2? \$\endgroup\$ – wb9688 Nov 17 '15 at 7:16
  • \$\begingroup\$ @wb9688 No idea, I only tested it with Python 3 \$\endgroup\$ – phase Nov 17 '15 at 7:17
  • \$\begingroup\$ I just tested, and it works with Python 2 \$\endgroup\$ – wb9688 Nov 17 '15 at 7:25
2
\$\begingroup\$

Ruby, 70

x=$_+"
"
1while x.sub! /^(( *).*):
((\2 .*?
)*)/,'\1 {
\3\2}
'
$><<x

Adds a trailing newline. Does not need the indent block-size parameter.

Run this with -n0 (this is really 68+2). Thank you greatly to @primo for saving over a dozen bytes.

\$\endgroup\$
  • \$\begingroup\$ I think -p0 also works for ruby (-0 reads all input at once, -p stores stdin into $_, and auto-prints it at the end). \$\endgroup\$ – primo Nov 16 '15 at 8:47
  • \$\begingroup\$ @primo Good point. In case it wasn't clear with my comment above, this isn't a port of your code, but my own work that does exactly what yours does (but with more bytes) \$\endgroup\$ – Not that Charles Nov 16 '15 at 15:01
  • \$\begingroup\$ I understood correctly, just providing a tip to remove the (rather verbose) x=$<.readlines*''. While I'm doing that, sub! also has a two parameter overload (rather than one paramater + block) that accepts a replacement string, so you can use \1, \2, etc. instead of needing to concatenate it all. \$\endgroup\$ – primo Nov 16 '15 at 15:08
  • \$\begingroup\$ @primo Thanks! I tried the two-parameter version before and abandoned it at some point last night. \$\endgroup\$ – Not that Charles Nov 16 '15 at 16:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.