Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Given an input of a string representing a function definition, output the string with newlines and spaces inserted so that the function's arguments are newline-separated and aligned.

The input string will follow the following pattern:

  • First, it will start with a prefix, which is always at least one character long and does not contain any of the characters ,().

  • An open parenthesis (() will then mark the beginning of the argument list.

  • A list of zero or more arguments will then follow. These are separated by the string ", " (a comma and then a space). None of the arguments will contain any of the characters ,().

  • A close parenthesis ()) will mark the end of the argument list.

  • Lastly, a postfix may be found, which is zero or more characters long and may contain the characters ,().

The input string will consist solely of printable ASCII (which means it will never contain a newline).

The output must be:

  • The prefix, copied down verbatim, and the open parenthesis.

  • The argument list, this time separated not by ", " but by a comma, newline, and as many spaces as is needed to vertically align the first character of each argument.

  • The close paren and postfix (if it exists) verbatim.

Since this is , the shortest code in bytes will win.

Test cases (format: single-line input followed by output followed by double newline):

def foo(bar, baz, quux):
def foo(bar,
        baz,
        quux):

int main() {
int main() {

fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {
fn f(a: i32,
     b: f64,
     c: String) -> (String, Vec<i32>) {

function g(h) {
function g(h) {

def abc(def, ghi, jkl, mno)
def abc(def,
        ghi,
        jkl,
        mno)

x y z(x, y, z) x, y, z)
x y z(x,
      y,
      z) x, y, z)
share|improve this question

Haskell, 115 bytes

import Data.Lists
f x|(a,b:c)<-span(/='(')x,(d,e)<-span(/=')')c=a++b:intercalate(",\n "++(a>>" "))(splitOn", "d)++e

Usage example:

*Main> putStrLn $ f "fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {"
fn f(a: i32,
     b: f64,
     c: String) -> (String, Vec<i32>) {

How it works:

bind
  a: everything before the first (
  b: the first (
  c: everything after the first (
  d: everything of c before the first )
  e: everything of c from the first ) to the end

construct the output string by concatenating
  a
  b
  splitting d at the argument separator ", " and rejoining it with ",\n " followed by (length a) spaces    
  e
share|improve this answer
    
a>>" " is really clever... – Actorclavilis Feb 8 at 23:10

Japt, 23 bytes

¡Y?X:Xr',",
"+SpUb'(}')

Test it online!

How it works

               // Implicit: U = input string
¡        }')   // Map each item X and index Y in U.split(")") to:
Y?X            //  If Y is non-zero, X. This keeps e.g. "(String, Vec<i32>)" from being parsed.
:Xr',",\n"+    //  Otherwise, X with each comma replaced with ",\n" concatenated with
SpUb'(         //  U.indexOf("(") spaces.
               // Implicit: re-join with ")", output
share|improve this answer

Perl, 62 52 + 2 = 54 bytes

s/\(.*?\)/$a=$"x length$`;$&=~s|(?<=,)[^,]+|\n$a$&|gr/e

Requires the -p flag:

$ echo "x y z(x, y, z) x, y, z)
fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {" | \
perl -pe's/\(.*?\)/$a=$"x length$`;$&=~s|(?<=,)[^,]+|\n$a$&|gr/e'
x y z(x,
      y,
      z) x, y, z)
fn f(a: i32,
     b: f64,
     c: String) -> (String, Vec<i32>) {

How it works:

# '-p' reads first line into $_ and will also auto print at the end
s/\(.*?\)/             # Match (...) and replace with the below
  $a=$"x length$`;     # $` contains all the content before the matched string
                       # And $" contains a literal space 
  $&=~s|               # Replace in previous match
    (?<=,)[^,]+        # Check for a , before the the string to match
                       # This will match ' b: f64', ' c: String'
  |\n$a$&|gr/e         # Replace with \n, [:spaces:] and all the matched text
share|improve this answer

Retina, 31 bytes

(?<=^([^(])*\([^)]*,) 
¶ $#1$* 

Note the spaces at the end of both lines.

We replace every space which has the regex ^([^(])*\([^)]*, before it. The replacing string will be a newline, and the number of the captures with ([^(])* plus one spaces.

A more coherent explanation comes later.

Try it online here.

share|improve this answer

ES6, 68 67 bytes

s=>s.replace(/\(.*?\)/,(s,n)=>s.replace/, /g, `,
 `+` `.repeat(n)))

This works by extracting the argument list from the original string, and replacing each argument separator with indentation calculated from the position of the argument list within the original string.

Edit: Saved 1 byte thanks to @ETHproductions.

share|improve this answer
    
I was wondering why you did .split`, `.join(...) instead of .replace(...). Turns out the other is a byte shorter: s=>s.replace(/\(.*?\)/,(s,n)=>s.replace(/, /g,`,\n `+` `.repeat(n))) – ETHproductions Feb 9 at 16:37

Retina, 47 bytes

Byte count assumes ISO 8859-1 encoding.

m+`^(([^(]+.)[^,)]+,) (.+)
$1¶$2$3
T`p` `¶.+?\(

Try it online!

share|improve this answer

Pyth, 35 30 bytes

+j++\,b*dhxz\(c<zKhxz\)", ">zK

Try it here!

Explanation:

+j++\,b*dhxz\(c<zKhxz\)", ">zK    # z = input()

                 Khxz\)           # Get index of the first ")"
               <z                 # Take the string until there...
              c        ", "       # ...and split it on the arguments
 j                                # Join the splitted string on...
  ++                              # ...the concatenation of...
    \,b                           # ...a comma followed by a newline...
       *dhxz\(                    # ...followed by the right amount of spaces = index of the first "(" + 1
+                         >zK     # Concat the resulting string with the postfix
share|improve this answer

JavaScript (ES6), 85

s=>s.replace(/^.*?\(|[^),]+, |.+/g,(x,p)=>[a+x,a=a||(p?`
`+' '.repeat(p):a)][0],a='')

Test

f=s=>s.replace(/^.*?\(|[^),]+, |.+/g,(x,p)=>[a+x,a=a||(p?`
`+' '.repeat(p):a)][0],a='')

console.log=x=>O.textContent+=x+'\n'

;['def foo(bar, baz, quux):',
  'int main() {',
  'fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {',
  'function g(h) {',
  'def abc(def, ghi, jkl, mno)',
  'x y z(x, y, z) x, y, z)']
.forEach(t=>console.log(t+'\n'+f(t)+'\n'))
<pre id=O></pre>

share|improve this answer
    
I'm sorry, I was mistaking, was running the code in my console and the output was something like this: "x y z(x as you can see the " thats why I was thinking it was one space off. Hence the deletion – andlrc Feb 8 at 22:44
    
@dev-null that happens to me all the time. – edc65 Feb 8 at 22:48

Groovy, 137 89 95 bytes

Groovy is not the "Right Tool for the Job"™. Edit: It works just fine when you have someone with a brain using it...

f={s=(it+' ').split(/\0/)
s[0].replace(',',',\n'+(' '*it.indexOf('(')))+')'+s[1..-1].join(')')}

Tests:

println f("def foo(bar, baz, quux):")
println f("int main() {")
println f("fn f(a: i32, b: f64, c: String) -> (String, Vec<i32>) {")
println f("function g(h) {")
println f("def abc(def, ghi, jkl, mno)")
println f("x y z(x, y, z) x, y, z)")

Somewhat ungolfed:

f = {String it ->
    def str = (it + ' ').split(/\)/)
    return (str[0].replace (',', ',\n'+(' ' * it.indexOf('('))) + ')' + str[1])
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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