7
\$\begingroup\$

Your program's input is a string containing whitespaces, parentheses, and other characters. The string is assumed to be parenthesed correctly, i.e. each right parenthesis matches a unique left parenthesis and vice versa : so the program is allowed to do anything on incorrectly parenthesed strings, such as )abc, (abc or )abc(. The character interval between a left parenthesis and the corresponding right parenthesis (including the parentheses) is called a parenthesed interval. Your program's job is to decompose the string into blocks according to the rules below, and output the result as a "vertical list", with one block per line.

Now, two characters in the string are in the same block if either

(a) there is no whitespace character strictly between them

or

(b) there is a parenthesed interval containing them both.

Also,

(c) Whitespaces not in any parenthesed interval are mere separators and to be discarded in the decomposition. All the other characters (including whitespaces) are retained.

For example, if the input is

I guess     () if(you say ( so)), I'll have((  ))to pack my (((things))) and go

The output should be

I
guess
()
if(you say ( so)),
I'll
have((  ))to
pack
my
(((things)))
and
go

Another useful test (thanks to NinjaBearMonkey) :

Hit the ( Road (Jack Don't) come ) back (no (more ) ) no more

The output should be

Hit
the
( Road (Jack Don't) come )
back
(no (more ) )
no 
more

The shortest code in bytes wins.

\$\endgroup\$
  • \$\begingroup\$ You might want to have something like ((foo) bar) in the test case where all parentheses aren't closed at once. \$\endgroup\$ – NinjaBearMonkey Jul 9 '16 at 15:37
  • 1
    \$\begingroup\$ @NinjaBearMonkey if(you say ( so)), \$\endgroup\$ – Neil Jul 9 '16 at 15:42
  • 1
    \$\begingroup\$ A test case including something like a( b )c( d )e would also be good. \$\endgroup\$ – Martin Ender Jul 9 '16 at 19:22
  • 1
    \$\begingroup\$ Can the input start or end with spaces? \$\endgroup\$ – Martin Ender Jul 9 '16 at 19:27
3
\$\begingroup\$

MATL, 22 bytes

j0G40=G41=-YsG32=*g(Yb

Try it online!

Explanation

This uses a builtin function for splitting a string at spaces. To avoid splitting at spaces between matching parentheses, these are first detected and replaced by character 0. This is not detected as a space by the string-splitting function, but is treated as a space by the implicit display function.

j        % Take input as a string. 
0        % Push 0
G40=     % True for occurrences of '(' 
G41=     % True for occurrences of ')' 
-Ys      % Subtract and cumulative sum. Positive values correspond to characters
         % between matching parentheses
G32=     % True for occurrences of space
*g       % Multiply, convert to logical. Gives true for spaces between matching
         % parentheses
(        % Assign 0 to those positions. This replaces spaces between matching
         % parentheses by character 0
Yb       % Split at spaces, treating consecutive spaces as a single space.
         % Character 0 does not cause splitting, but is displayed as a space
\$\endgroup\$
  • \$\begingroup\$ @Ewan Thanks for the accept! However, although you can accept another answer at any time (if a shorter answer shows up), it's common to leave the challenge unaccepted for a few days, to encourage people to answer \$\endgroup\$ – Luis Mendo Jul 10 '16 at 7:25
8
\$\begingroup\$

Retina, 31 bytes

S-_` (?=([^)]|(\()|(?<-2>.))+$)

Try it online!

This is a standard exercise in balancing groups. We simply match all spaces from which we can reach the end of the string while passing only correctly matched parentheses (since the ones we don't want to remove are followed by an unmatched closing parenthesis), and split the input around those matches. The _ option removes empty segments in case there are several spaces in a row and the - suppresses the default behaviour to include captured substrings in the result.

\$\endgroup\$
7
\$\begingroup\$

Retina, 30 bytes

!`(\(()|(?<-2>)\)|(?(2).|\S))+

1 byte shorter...

Try it here.

\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 61 bytes

s=>s.replace(/[()]| +/g,c=>(c<`(`?n:c<`)`?++n:n--)?c:`
`,n=0)

Works by matching all parentheses and runs of spaces, maintaining a count of the nesting depth and replacing the run with a newline if the nesting depth is zero.

\$\endgroup\$
2
\$\begingroup\$

APL, 55 53 bytes

{⍵⊂⍨((⍵≠' ')∨~b)×+\1,¯1↓(b←0=+\1 ¯1 0['()'⍳⍵])∧⍵=' '}

To be run in ⎕ml←3. Usual trick: cumulative scans of 1s and -1s to identify the areas enclosed by parentheses. Where the cumulative sum is 0, then we are outside parentheses. Boolean and the vector with the boolean vector with 1s where there are spaces. Rotate by 1 to the right inserting a 1 on the left. Build another running sum where each change identifies a segment. We're almost done, but we still need to remove the spaces at level 0. That's what the left side of the multiplication does: it zeroes out the level 0 spaces in the running sum. The dyadic enclose ⊂⍨ splits every time the running sum changes while throwing away the zeroes.

\$\endgroup\$
  • \$\begingroup\$ Umm... I don't see a second usage of s in your expression, so you should be able to save two bytes by removing the s←. \$\endgroup\$ – Zacharý Dec 4 '16 at 0:45
  • \$\begingroup\$ Indeed! Well spotted! \$\endgroup\$ – lstefano Dec 5 '16 at 12:06
  • \$\begingroup\$ I assume you brute-forced the year game, and just got lucky that Dan missed something? \$\endgroup\$ – Zacharý Jul 31 '17 at 22:11
  • \$\begingroup\$ My guess is that all those who scored less than 750 in the Year Game 2016 brute forced it. In fact, I know all the Italian ones did, because I know them personally. So why did we get different results? I'll leave the question without an answer. I am sure you noticed the little commute up there. \$\endgroup\$ – lstefano Aug 2 '17 at 6:13
  • \$\begingroup\$ I've heard from Adám what happened there ... FINNS! \$\endgroup\$ – Zacharý Aug 2 '17 at 23:28
1
\$\begingroup\$

Perl, 80 bytes (79 + -n flag)

$r=qr/[^\(\)]*(\((??{$r})\))?[^\(\)]*/;/((([^ \(]*(\($r\))?)+ *)(?{say$^N}))+/

Run with :

perl -M5.010 -ne '$r=qr/[^\(\)]*(\((??{$r})\))?[^\(\)]*/;/((([^ \(]*(\($r\))?)+ *)(?{say$^N}))+/'

It might not be easy to read, so here are the explanations :

# The first regex ($r) is meant to match anything between two matching parenthesis
$r = qr/ [^\(\)]*         # match anything but parenthesis
         (\(               # match an opening parenthesis
           (??{$r})        # reccursive call to the same regex
          \)               # match a closing parenthesis
         )?               # the 3 previous lines are optionnal
         [^\(\)]*         # match anything but parenthesis
       /x;       

# The second regex kinda split the input according to the rules
/(
    (
     ([^ \(]*           # match anything but spaces and parenthesis
      (\($r\))?          # optionnal : match an opening parenthesis, then let the 
                         #   first regex match anything until the matching closing parenthesis.
     )+                 # repeat (no spaces out of parenthesis has been found yet)
     \ *               # match the space(s) that delimite the outputed lines.
    )                  
    (?{say$^N})       # execute the code 'say $^N' which prints the content 
                      #   of the last closed group (which is the line above)
 )+                 # repeat as many times as possible
/x 
\$\endgroup\$
1
\$\begingroup\$

C (32-bit), 115 113 bytes

s,*P;main(q,c){char*p=P=1[P=c],*o=p;for(;c=*p++;c^=32,s+=c^9?c==8:-1,*o=s|c?c^32:10,o+=s|c||q,q=c);*o=0;puts(P);}

Compile as 32-bit C, and pass input string as command-line argument. E.g.:

~/golf/ λ gcc -m32 -w golf.c && ./a.out "Hit the ( Road (Jack Don't) come ) back (no (more ) ) no more"
Hit
the
( Road (Jack Don't) come )
back
(no (more ) )
no
more
\$\endgroup\$

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.