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 code-golf, 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)
10 Answers 10
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
-
\$\begingroup\$
a>>" "is really clever... \$\endgroup\$fmt– fmt2016年02月08日 23:10:38 +00:00Commented Feb 8, 2016 at 23:10
Japt, 23 bytes
¡Y?X:Xr',",
"+SpUb'(}')
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
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
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.
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.
-
\$\begingroup\$ 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)))\$\endgroup\$ETHproductions– ETHproductions2016年02月09日 16:37:06 +00:00Commented Feb 9, 2016 at 16:37
Pyth, (削除) 35 (削除ここまで) 30 bytes
+j++,円b*dhxz\(c<zKhxz\)", ">zK
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
Groovy, (削除) 137 (削除ここまで) (削除) 89 (削除ここまで) 95 bytes
(削除) Groovy is not the "Right Tool for the Job"TM. (削除ここまで) 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])
}
Retina, 47 bytes
Byte count assumes ISO 8859-1 encoding.
m+`^(([^(]+.)[^,)]+,) (.+)
1ドル¶2ドル3ドル
T`p` `¶.+?\(
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>
-
\$\begingroup\$ I'm sorry, I was mistaking, was running the code in my console and the output was something like this:
"x y z(xas you can see the"thats why I was thinking it was one space off. Hence the deletion \$\endgroup\$Andreas Louv– Andreas Louv2016年02月08日 22:44:37 +00:00Commented Feb 8, 2016 at 22:44 -
\$\begingroup\$ @dev-null that happens to me all the time. \$\endgroup\$edc65– edc652016年02月08日 22:48:25 +00:00Commented Feb 8, 2016 at 22:48