# 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
    }