This is an alternate version of this earlier challenge with a twist that adds a significant bit of difficulty.

Like last time, you are going to be given a string containing some alphabetic characters along with [ and ]. Your task is to split into sections that are enclosed in a "group" created by [...] and those that are not. e.g.


However unlike last time, this time a "group" must be non-empty. This means it must contain at least one character. So when there are [] next to each other they don't form a group. For example:


The first pair of brackets is empty so it can't form a group. The second one does so it counts as a group and we split it. Notice that the non-group portions can be empty, it's just the groups that cannot.

Additionally when there is a conflict where two possible groups could be made: like co[[x]t or m[[e]]it, we will always choose the smallest valid group. In the case of a tie we choose the group that starts the furthest to the left.

Any [s left without a match are just regular characters and appear in the output.

So in co[[x]t we could do co [x t, but we could also do co[ x t. Since the group here is either [x or x we choose the smaller one and the result is co[ x t. In the second case me[[e]]it there are 4 ways to make groups here, but unambiguously me[ e ]it results in the smallest group.

If we have me[[]]yt then the smallest group would be [], but that's not a group, so our options are me [ ]yt and me[ ] yt so we choose me [ ]yt because that group starts further to the left.

Your task will be to take a non-empty string of characters a through z plus two brackets of your choice ([], {}, () and <>) and to split it as described above, providing a list of strings as output.

In cases where a group is on the boundary of the string, e.g. aaa[b] or [ems]ee you may choose to include or omit an empty string "" on that boundary. The test cases always include them.

This is . Answers will be scored in bytes with the goal being to minimize the size of your source code.

Test cases

go[cat]me -> "go" "cat" "me"
absbn[mesl]meslo[eyyis]me -> "absbn" "mesl" "meslo" "eyyis" "me"
absm[]mm[m] -> "absm[]mm" "m" ""
co[[x]t -> "co[" "x" "t"
me[[e]]t -> "me[" "e" "]t"
me[[]]yt -> "me" "[" "]yt"
mon[g]]u -> "mon" "g" "]u"
msy]mesl -> "msy]mesl"
eoa[m -> "eoa[m"
a[b[ -> "a[b["
mesi]mmp[mo -> "mesi]mmp[mo"
meu[ems[mela[] -> "meu[ems" "mela[" ""
w[[[] -> "w[" "[" ""
[foo]foobar[bar] -> "" "foo" "foobar" "bar" ""
ab[][]cd -> "ab" "][" "cd"
me[[[][]]yt -> "me[","[","","]","yt"
mem[[[[]]] -> "mem[[" "]" "]]" 
mem[ooo[]]t -> "mem[ooo" "]" "t"

4 Answers 4


Retina 0.8.2, 45 bytes


Try it online! Link includes test suite that switches between [] and <> and separates the output lines for each case with - for convenience. Explanation:


Include only capture group 1 in the results.


Look for a minimal group...


... that does not overlap with...


... a smaller group.


Haskell, Reference answer

n!('[':x)|']':y<-drop n x="":take n x:n!y
f x=foldl(\x->(>>=)x.(!))[x][1..length x]

Try it online!

Since there seems to be some issues with understanding exactly the specifications, I thought I would post my Haskell reference solution. It's how I have been checking the test cases. It's golfed just enough to be a valid answer here, but I've left it as a CW since it could certainly be golfed better.

If you are unclear about anything in the question please ask, but this should serve as a way that you can test out cases without having to wait for me to respond.


The algorithm here is very simple. First we split all occurrences of the pattern [.], preferring ones to the right. Then we split all occurrences of [..], then [...], then [....] up until the length of the list.

This never splits on empty groups, prioritizes smaller groups and when groups are equal sizes prioritizes to the right.


Python3, 255 bytes:

def f(l):
 if(j:=[(x,y) for x in r(q)for y in r(x+1,q)if l[x]=='['and l[y]==']'and y-x>1]):
  m=min(j,key=lambda x:[not l[x[0]:x[1]].isalpha(),x[1]-x[0],x[0]])
  yield l[:m[0]];yield l[m[0]+1:m[1]];yield from f(l[m[1]+1:])
 else:yield l

Try it online!


Python, 150 bytes

def f(s):(n:=len(s));g,l,i=min([[s[i]>"[",s[i+2:].find("]")%n+3,i]for i in range(n)]+[3*[1]]);return[s]*(g|(l>n))or f(s[:i])+[s[i+1:i+l-1]]+f(s[i+l:])

Attempt This Online!

Old Python, 168 bytes

def f(s):
 while r:
  if any(m:="".join(d)for x,*d,y in zip(*S)if[x,y]==[*"[]"]):x,y=s.split(f"[{m}]",1);return*f(x),m,*f(y)
 return s,

Attempt This Online!

Old Python, 174 bytes

def f(s):
 while r>r[:1]:
  if any(m:="".join(d)for x,*d,y in zip(*S)if[x,y]==[*"[]"]):x,y=s.split(f"[{m}]",1);return*f(x),m,*f(y)
 return s,

Attempt This Online!

Thee requirement of having to pick a shorter match over a potentially overlapping earlier but longer match is too much for my regex skills.

This approach finds the shortest (first if ties) match, splits the string there and recurses on the ends.

Wrong Python, 53 bytes

lambda s:re.split(r"\[((?:[^][]+)|\[)\]",s)
import re

Attempt This Online!

I must admit I do not fully understand the rules. But this solves all test cases EDIT: did solve at the time.


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.