61 lines
1.6 KiB
Text
61 lines
1.6 KiB
Text
\ 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
|