10
\$\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\$
10
  • 1
    \$\begingroup\$ Can we assume that the input contains no comments? \$\endgroup\$ Oct 19, 2015 at 7:19
  • 1
    \$\begingroup\$ @MartinBüttner It may contain comments, but the comments won't contain ':'. Basically, yes. \$\endgroup\$
    – jado
    Oct 19, 2015 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\$ Oct 19, 2015 at 8:11
  • 1
    \$\begingroup\$ I've never seen a label anywhere but the beginning of a line. \$\endgroup\$ Oct 19, 2015 at 13:20
  • 2
    \$\begingroup\$ I've just been reminded of how much I hate Java. \$\endgroup\$
    – lirtosiast
    Nov 16, 2015 at 4:46

3 Answers 3

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\$
1
  • \$\begingroup\$ i just wrote this in ruby \$\endgroup\$ Nov 16, 2015 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\$
5
  • \$\begingroup\$ Can you include an explanation? \$\endgroup\$
    – TanMath
    Nov 16, 2015 at 5:22
  • \$\begingroup\$ @TanMath Added the algorithm I used \$\endgroup\$
    – jado
    Nov 16, 2015 at 5:39
  • \$\begingroup\$ Does it work with Python 2? \$\endgroup\$
    – wb9688
    Nov 17, 2015 at 7:16
  • \$\begingroup\$ @wb9688 No idea, I only tested it with Python 3 \$\endgroup\$
    – jado
    Nov 17, 2015 at 7:17
  • \$\begingroup\$ I just tested, and it works with Python 2 \$\endgroup\$
    – wb9688
    Nov 17, 2015 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\$
4
  • \$\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, 2015 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\$ Nov 16, 2015 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, 2015 at 15:08
  • \$\begingroup\$ @primo Thanks! I tried the two-parameter version before and abandoned it at some point last night. \$\endgroup\$ Nov 16, 2015 at 16:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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