\ Given a low and high limit, create an array containing the numbers in the \ range, inclusive: : n:gen-range \ low hi -- a \ make sure they are in order: 2dup n:> if swap then \ fill the array with the values: [] ' a:push 2swap loop ; \ Take a string, either "X" or "X-Y", and correctly return either a number (if \ "X") or an array of numbers (if "X-Y"): : n:expand-one \ s -- n | a[n,..m] \ First see if we can parse a number. This works in the "X" case: dup >n null? if \ Failed >n because it's (possibly) "X-Y" drop \ not a valid number, might be a range \ We'll use a capturing regex to handle the different cases correctly: /(-?[0-9]+)-(-?[0-9]+)/ tuck r:match \ If the regex matches three (the whole string, plus the two captured \ expressions) then it's a valid "X-Y": 3 n:= if 1 r:@ >n swap 2 r:@ >n nip \ generate the range: n:gen-range else \ The regex didn't match, so we got garbage. Therefore, return a 'null': drop null then else \ It was a "X", just drop the original string: nip then ; \ Take an array (possibly) containing other arrays, and flatten any contained \ arrays so the result is a simple array: : a:flatten \ a1 -- a2 [] >r ( nip array? if a:flatten r> swap a:+ >r else r> swap a:push >r then ) a:each drop r> ; \ Take a comma-delimited string of ranges, and expand it into an array of \ numbers: : n:range-expand \ str -- a "," s:/ ' n:expand-one a:map a:flatten ; \ Process a list: "-6,-3--1,3-5,7-11,14,15,17-20" n:range-expand \ print the expanded list: . cr bye