# Ruby, <s>405</s> <s>403</s> <s>401</s> 400 bytes A wise man (Jamie Zawinski) once said, "Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems." I don't think I fully appreciated that quote until I tried to solve this problem with recursive regex. Initially, the regex cases seemed simple, until I had to deal with the edge cases involving letters adjacent to brackets, and then I knew that I was in hell. [Anyways, run it online here with test cases](https://repl.it/C9sG/4) <!-- language: lang-ruby --> ->s{s.gsub!(/{(-?\w+)..(-?\w+)(..(\d+))?}/){x,y=$1,$2;a,b,c=[x,y,$4].map &:to_i $1[/\d/]?0:(a,b=x,y) k=a<b ?[*a..b]:[*b..a].reverse ?{+0.step(k.size-1,$4?c:1).map{|i|k[i]}*?,+?}} r=1 t=->x{x[0].gsub(/^{(.*)}$/){$1}.scan(/(({(\g<1>|,)*}|[^,{}]|(?<=,|^)(?=,|$))+)/).map{|i|i=i[0];i[?{]?r[i]:i}.flatten} r=->x{i=x.scan(/({(\g<1>)*}|[^{} ]+)/).map(&t) i.shift.product(*i).map &:join} s.split.map(&r)*' '} Ungolfed: <!-- language: lang-ruby --> ->s{ s.gsub!(/{(-?\w+)..(-?\w+)(..(\d+))?}/){ # Replace all range-type brackets {a..b..c} x,y=$1,$2;a,b,c=[x,y,$4].map &:to_i # Set up int variables $1[/\d/]?0:(a,b=x,y) # Use int variables for a,b if they're numbers k=a<b ?[*a..b]:[*b..a].reverse # Create an array for the range in the correct direction '{'+ # Return the next bit surrounded by brackets 0.step(k.size-1,$4?c:1).map{|i|k[i] # If c exists, use it as the step size for the array }*',' # Join with commas +'}' } r=1 # Dummy value to forward-declare the parse function `r` t=->x{ # Function to parse a bracket block x=x[0].gsub(/^{(.*)}$/){$1} # Remove outer brackets if both are present # x[0] is required because of quirks in the `scan` function x=x.scan(/(({(\g<1>|,)*}|[^,{}]|(?<=,|^)(?=,|$))+)/) # Regex black magic: collect elements of outer bracket x.map{|i|i=i[0];i[?{]?r[i]:i}.flatten # For each element with brackets, run parse function } r=->x{ # Function to parse bracket expansions a{b,c}{d,e} i=x.scan(/({(\g<1>)*}|[^{} ]+)/) # Regex black magic: scan for adjacent sets of brackets i=i.map(&t) # Map all elements against the bracket parser function `t` i.shift.product(*i).map &:join # Combine the adjacent sets with cartesian product and join them together } s.split.map(&r)*' ' # Split on whitespace, parse each bracket collection # and re-join with spaces }