# Range expansion

Range expansion
You are encouraged to solve this task according to the task description, using any language you may know.
A format for expressing an ordered list of integers is to use a comma separated list of either
• individual integers
• Or a range of integers denoted by the starting integer separated from the end integer in the range by a dash, '-'. (The range includes all integers in the interval including both endpoints)
• The range syntax is to be used only for, and for every range that expands to more than two values.

Example
The list of integers:

-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20

Is accurately expressed by the range expression:

-6,-3-1,3-5,7-11,14,15,17-20

(And vice-versa).

Expand the range description:

-6,-3--1,3-5,7-11,14,15,17-20

Note that the second element above, is the range from minus 3 to minus 1.

C.f. Range extraction

The function Expand takes a string and returns a corresponding array of integers. Upon syntax errors Constraint_Error is propagated: <lang Ada>with Ada.Text_IO; use Ada.Text_IO; procedure Test_Range_Expansion is

```  type Sequence is array (Positive range <>) of Integer;
function Expand (Text : String) return Sequence is
To    : Integer := Text'First;
Count : Natural := 0;
Low   : Integer;
function Get return Integer is
From : Integer := To;
begin
if Text (To) = '-' then
To := To + 1;
end if;
while To <= Text'Last loop
case Text (To) is
when ',' | '-' => exit;
when others => To := To + 1;
end case;
end loop;
return Integer'Value (Text (From..To - 1));
end Get;
begin
while To <= Text'Last loop -- Counting items of the list
Low := Get;
if To > Text'Last or else Text (To) = ',' then
Count := Count + 1;
else
To := To + 1;
Count := Count + Get - Low + 1;
end if;
To := To + 1;
end loop;
return Result : Sequence (1..Count) do
Count := 0;
To := Text'First;
while To <= Text'Last loop -- Filling the list
Low := Get;
if To > Text'Last or else Text (To) = ',' then
Count := Count + 1;
Result (Count) := Low;
else
To := To + 1;
for Item in Low..Get loop
Count := Count + 1;
Result (Count) := Item;
end loop;
end if;
To := To + 1;
end loop;
end return;
end Expand;
procedure Put (S : Sequence) is
First : Boolean := True;
begin
for I in S'Range loop
if First then
First := False;
else
Put (',');
end if;
Put (Integer'Image (S (I)));
end loop;
end Put;
```

begin

```  Put (Expand ("-6,-3--1,3-5,7-11,14,15,17-20"));
```

end Test_Range_Expansion;</lang>

Output:
```-6,-3,-2,-1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
```

## ALGOL 68

 This example is incorrect. Please fix the code and remove this message.Details: The task example was modified after discussion in the talk page.
Works with: ALGOL 68 version Revision 1 - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny
Works with: ELLA ALGOL 68 version Any (with appropriate job cards) - tested with release 1.8-8d

<lang algol68>MODE YIELDINT = PROC(INT)VOID;

MODE RANGE = STRUCT(INT lwb, upb); MODE RANGEINT = UNION(RANGE, INT);

OP SIZEOF = ([]RANGEINT list)INT: (

1. determine the length of the output array #
``` INT upb := LWB list - 1;
FOR key FROM LWB list TO UPB list DO
CASE list[key] IN
(RANGE value): upb +:= upb OF value - lwb OF value + 1,
(INT): upb +:= 1
ESAC
OD;
upb
```

);

PROC gen range expand = ([]RANGEINT list, YIELDINT yield)VOID:

``` FOR key FROM LWB list TO UPB list DO
CASE list[key] IN
(RANGE range): FOR value FROM lwb OF range TO upb OF range DO yield(value) OD,
(INT int): yield(int)
ESAC
OD;
```

PROC range expand = ([]RANGEINT list)[]INT: (

``` [LWB list: LWB list + SIZEOF list - 1]INT out;
INT upb := LWB out - 1;
```
1. FOR INT value IN # gen range expand(list, # ) DO #
1. (INT value)VOID:
```   out[upb +:= 1] := value
```
1. OD #);
``` out
```

);

test:(

``` []RANGEINT list = (-6, RANGE(-3, -1), RANGE(3, 5),  RANGE(7, 11), 14, 15, RANGE(17, 20));
print((range expand(list), new line))
```

)</lang>

Output:
```         -6         -3         -2         -1         +3         +4         +5         +7         +8         +9        +10        +11        +14        +15        +17        +18        +19        +20
```

## AutoHotkey

<lang AutoHotkey>msgbox % expand("-6,-3--1,3-5,7-11,14,15,17-20")

expand( range ) {

```   p := 0
while p := RegExMatch(range, "\s*(-?\d++)(?:\s*-\s*(-?\d++))?", f, p+1+StrLen(f))
loop % (f2 ? f2-f1 : 0) + 1
ret .= "," (A_Index-1) + f1
return SubStr(ret, 2)
```

}</lang>

## Bracmat

<lang bracmat> ( expandRanges

``` =   a b L
.     @( !arg
:   (#(?a:?b)|#?a "-" #?b)
(:?L|"," [%(expandRanges\$!sjt:?L))
)
&   whl
' (   (!L:&!b|(!b,!L))
: ?L
& -1+!b:~<!a:?b
)
& !L
|
)
```

& out\$(str\$(expandRanges\$"-6,-3--1,3-5,7-11,14,15,17-20")) </lang> Output:

`-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20`

## C

Recursive descent parser. <lang c>#include <stdio.h>

1. include <stdlib.h>
2. include <ctype.h>

/* BNFesque rangelist := (range | number) [',' rangelist] range := number '-' number */

int get_list(char *, char **); int get_rnge(char *, char **);

/* parser only parses; what to do with parsed items is up to

• the add_number and and_range functions */

1. define skip_space while(isspace(*s)) s++
2. define get_number(x, s, e) (x = strtol(s, e, 10), *e != s)

int get_list(char *s, char **e) { int x; while (1) { skip_space; if (!get_rnge(s, e) && !get_number(x, s, e)) break; s = *e;

skip_space; if ((*s) == '\0') { putchar('\n'); return 1; } if ((*s) == ',') { s++; continue; } break; } *e = s; printf("\nSyntax error at %s\n", s); return 0; }

int get_rnge(char *s, char **e) { int x, y; char *ee; if (!get_number(x, s, &ee)) return 0; s = ee;

skip_space; if (*s != '-') { *e = s; return 0; } s++; if(!get_number(y, s, e)) return 0; return add_range(x, y); }

void add_number(int x) { printf("%d ", x); }

int add_range(int x, int y) { if (y <= x) return 0; while (x <= y) printf("%d ", x++); return 1; }

int main() { char *end;

/* this is correct */ if (get_list("-6,-3--1,3-5,7-11,14,15,17-20", &end)) puts("Ok");

/* this is not. note the subtle error: "-6 -3" is parsed * as range(-6, 3), so synax error comes after that */ get_list("-6 -3--1,3-5,7-11,14,15,17-20", &end);

return 0; }</lang>

Output:
```-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
Ok
-6 -5 -4 -3 -2 -1 0 1 2 3
Syntax error at --1,3-5,7-11,14,15,17-20```

## C#

Works with: C sharp version 3.0

<lang csharp>using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions;

class Program {

```   static void Main(string[] args)
{
var rangeString = "-6,-3--1,3-5,7-11,14,15,17-20";
var matches = Regex.Matches(rangeString, @"((?<f>-?\d+)-(?-?\d+))|(-?\d+)");
```
```       var values = new List<string>();
foreach (var m in matches.OfType<Match>())
{
if (m.Length == 2)
{
continue;
}
```
```           var start = Convert.ToInt32(m.Groups["f"].Value);
var end = Convert.ToInt32(m.Groups["s"].Value) + 1;
```
```           values.AddRange(Enumerable.Range(start, end - start).Select(v => v.ToString()));
}
```
```       Console.WriteLine(string.Join(", ", values));
}
```

}</lang>

## C++

<lang cpp>#include <iostream>

1. include <sstream>
2. include <iterator>
3. include <climits>
4. include <deque>

// parse a list of numbers with ranges // // arguments: // is: the stream to parse // out: the output iterator the parsed list is written to. // // returns true if the parse was successful. false otherwise template<typename OutIter>

```bool parse_number_list_with_ranges(std::istream& is, OutIter out)
```

{

``` int number;
while (is >> number)
{
*out++ = number;
```
```   char c;
if (is >> c)
switch(c)
{
case ',':
continue;
case '-':
{
int number2;
if (is >> number2)
{
if (number2 < number)
return false;
while (number < number2)
*out++ = ++number;
char c2;
if (is >> c2)
if (c2 == ',')
continue;
else
return false;
else
return is.eof();
}
else
return false;
}
default:
return is.eof();
}
else
return is.eof();
}
// if we get here, something went wrong (otherwise we would have
// returned from inside the loop)
return false;
```

}

int main() {

``` std::istringstream example("-6,-3--1,3-5,7-11,14,15,17-20");
std::deque<int> v;
bool success = parse_number_list_with_ranges(example, std::back_inserter(v));
if (success)
{
std::copy(v.begin(), v.end()-1,
std::ostream_iterator<int>(std::cout, ","));
std::cout << v.back() << "\n";
}
else
std::cout << "an error occured.";
```

}</lang>

Output:
```-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
```

## Clojure

There is a split method in clojure.contrib, but I don't know if it is able to skip first character to so that `(split "-8--8") => (-8 -8)`. <lang clojure>(defn split [s sep]

```     (defn skipFirst x & xs :as s
```

(cond (empty? s) [nil nil] (= x sep) [x xs] true [nil s]))

```     (loop [lst '(), s s]
```

(if (empty? s) (reverse lst) (let [[hd trunc] (skipFirst s) [word news] (split-with #(not= % sep) trunc) cWord (cons hd word)] (recur (cons (apply str cWord) lst) (apply str (rest news)))))))

(defn parseRange x & xs :as s

```      (if (some #(= % \-) xs)
```

(defn rangeexpand [s]

``` (flatten (map parseRange (split s \,))))
```

> (rangeexpand "-6,-3--1,3-5,7-11,14,15,17-20") (-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20)</lang>

## Common Lisp

<lang lisp>(defun expand-ranges (string)

``` (loop
with prevnum = nil
for idx = 0 then (1+ nextidx)
for (number nextidx) = (multiple-value-list
(parse-integer string
:start idx :junk-allowed t))
append (cond
(prevnum
(prog1
(loop for i from prevnum to number
collect i)
(setf prevnum nil)))
((and (< nextidx (length string))
(char= (aref string nextidx) #\-))
(setf prevnum number)
nil)
(t
(list number)))
while (< nextidx (length string))))
```

CL-USER> (expand-ranges "-6,-3--1,3-5,7-11,14,15,17-20") (-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20)</lang>

## D

Translation of: Python

<lang d>import std.stdio, std.regex, std.string, std.conv, std.range;

int[] rangeExpand(in string txt) /*pure nothrow*/ {

```   typeof(return) result;
```
```   foreach (r; std.string.split(txt, ",")) {
const m = r.match(r"^(-?\d+)(-?(-?\d+))?\$").captures.array();
result ~= m[2].empty ? [to!int(m[1])] :
iota(to!int(m[1]), to!int(m[3])+1).array();
}
return result;
```

}

void main() {

```   rangeExpand("-6,-3--1,3-5,7-11,14,15,17-20").writeln();
```

}</lang>

Output:
`[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]`

## F#

<lang fsharp>open System.Text.RegularExpressions

// simplify regex matching with an active pattern let (|Regexp|_|) pattern txt =

```   match Regex.Match(txt, pattern) with
| m when m.Success -> [for g in m.Groups -> g.Value] |> List.tail |> Some
| _                -> None
```

// Parse and expand a single range description. // string -> int list let parseRange r =

``` match r with
| Regexp @"^(-?\d+)-(-?\d+)\$" [first; last] -> [int first..int last]
| Regexp @"^(-?\d+)\$"         [single]      -> [int single]
| _ -> failwithf "illegal range format: %s" r

```

let expand (desc:string) =

``` desc.Split(',')
|> List.ofArray
|> List.collect parseRange
```

printfn "%A" (expand "-6,-3--1,3-5,7-11,14,15,17-20")</lang>

Output:
`[-6; -3; -2; -1; 3; 4; 5; 7; 8; 9; 10; 11; 14; 15; 17; 18; 19; 20]`

## Go

A version rather strict with input <lang go>package main

import (

```   "fmt"
"strconv"
"strings"
```

)

const input = "-6,-3--1,3-5,7-11,14,15,17-20"

func main() {

```   fmt.Println("range:", input)
var r []int
var last int
for _, part := range strings.Split(input, ",") {
if i := strings.Index(part[1:], "-"); i == -1 {
n, err := strconv.Atoi(part)
if err != nil {
fmt.Println(err)
return
}
if len(r) > 0 {
if last == n {
fmt.Println("duplicate value:", n)
return
} else if last > n {
fmt.Println("values not ordered:", last, ">", n)
return
}
}
r = append(r, n)
last = n
} else {
n1, err := strconv.Atoi(part[:i+1])
if err != nil {
fmt.Println(err)
return
}
n2, err := strconv.Atoi(part[i+2:])
if err != nil {
fmt.Println(err)
return
}
if n2 < n1+2 {
fmt.Println("invalid range:", part)
return
}
if len(r) > 0 {
if last == n1 {
fmt.Println("duplicate value:", n1)
return
} else if last > n1 {
fmt.Println("values not ordered:", last, ">", n1)
return
}
}
for i = n1; i <= n2; i++ {
r = append(r, i)
}
last = n2
}
}
fmt.Println("expanded:", r)
```

}</lang>

## Groovy

1. translate the task's range syntax into Groovy range syntax
2. wrap with list delimiters
3. evaluate the script expression
4. flatten the nested lists
5. express as a string
6. unwrap the list delimiters

<lang groovy>def expandRanges = { compressed ->

```   Eval.me('['+compressed.replaceAll(~/(\d)-/, '\$1..')+']').flatten().toString()[1..-2]
```

}</lang> Test: <lang groovy>def s = '-6,-3--1,3-5,7-11,14,15,17-20' println (expandRanges(s))</lang>

Output:
`-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20`

Given either of the below implementations of `expandRange`: <lang haskell>> expandRange "-6,-3--1,3-5,7-11,14,15,17-20" [-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]</lang>

### With conventional list processing

<lang haskell>expandRange :: String -> [Int] expandRange = concatMap f . split ','

``` where f str@(c : cs) | '-' `elem` cs = [read (c : a) .. read b]
where (a, _ : b) = break (== '-') cs
```

split :: Eq a => a -> [a] -> a split delim [] = [] split delim l = a : split delim (dropWhile (== delim) b)

``` where (a, b) = break (== delim) l</lang>
```

### With a parser

expandRange :: String -> [Int] expandRange s = case parse rangeParser "" s of Right l -> l

rangeParser :: Parser [Int] rangeParser = liftM concat \$ item `sepBy` char ','

``` where item = do
n1 <- num
n2 <- option n1 \$ char '-' >> num
return [n1 .. n2]
num :: Parser Int
num = liftM read \$ liftM2 (++)
(option "" \$ string "-")
(many1 digit)</lang>
```

## Icon and Unicon

<lang Icon>procedure main() s := "-6,-3--1,3-5,7-11,14,15,17-20" write("Input string  := ",s) write("Expanded list  := ", list2string(range_expand(s)) | "FAILED") end

procedure range_expand(s) #: return list of integers extracted from an ordered string representation local R,low,high R := []

s ? until pos(0) do {

```  put(R,low := integer(tab(upto(',-')|0))| fail)           # get lower bound
if ="-" || (high := integer(tab(find(",")|0))|fail) then
until low = high do put(R,low +:= 1)                  # find range
=","
}
```

return R end

procedure list2string(L) #: helper function to convert a list to a string local s

```  every (s := "[ ") ||:= !L || " "
return s || "]"
```

end</lang>

Output:
```Input string      := -6,-3--1,3-5,7-11,14,15,17-20
Expanded list   := [ -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 ]```

## J

<lang j>require'strings' to=: (+ i.)/@:(0 1 + -~/\) num=: _&". normaliz=: rplc&(',-';',_';'--';'-_')@,~&',' lumps=:<@(num`([:to num;._1@,~&'-')@.('-'&e.));._1 rngexp=: ;@lumps@normaliz</lang>

Example:

<lang j> rngexp '-6,-3--1,3-5,7-11,14,15,17-20' _6 _3 _2 _1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</lang>

## Java

<lang java>import java.util.*; import java.util.regex.*;

class Range implements Enumeration {

``` private int clower, cupper;
private int value;
private boolean inrange;
private Scanner ps = null;
private String ss;
```
``` private static String del = "\\s*,\\s*";
```
``` public Range(String s) {
ss = s;
reset();
}
```
``` public boolean hasMoreElements() {
return (inrange && (value >= clower && value <= cupper)) || ps.hasNext();
}
```
``` public Object nextElement() throws NoSuchElementException {
if (!hasMoreElements())
throw new NoSuchElementException();
if (inrange && (value >= clower && value <= cupper)) {
value++;
return value-1;
}
inrange = false;
String n = ps.next();
if (n.matches("[+-]?\\d+-[+-]?\\d+")) {
Scanner ls = new Scanner(n);
ls.findInLine("([+-]?\\d+)-([+-]?\\d+)");
MatchResult r = ls.match();
clower = Integer.parseInt(r.group(1));
cupper = Integer.parseInt(r.group(2));
value = clower+1;
inrange = true;
ls.close();
return clower;
}
return Integer.parseInt(n);
}

public void reset() {
if (ps != null)
ps.close();
ps = new Scanner(ss).useDelimiter(del);
inrange = false;
}
```
``` protected void finalize() throws Throwable {
ps.close();
super.finalize();
}
```

}

class rangexp {

``` public static void main(String[] args) {
Range r = new Range("-6,-3--1,3-5,7-11,14,15,17-20");
while (r.hasMoreElements()) {
System.out.print(r.nextElement() + " ");
}
System.out.println();
}
```

}</lang>

## K

<lang k>grp : {1_'(&x=*x)_ x:",",x} pos : {:[3=l:#p:&"-"=x;0,p@1;2=l;p;0=*p;,0;0,p]} conv: 0\${(x;1_ y)}/'{(pos x)_ x}' expd: {,/@[x;&2=#:'x;{(*x)+!1+,/-':x}]} rnge: {expd@conv grp x}</lang>

Example:

<lang k> rnge "-6,-3--1,3-5,7-11,14,15,17-20" -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</lang>

## Liberty BASIC

<lang lb>print ExpandRange\$( "-6,-3--1,3-5,7-11,14,15,17-20") end

function ExpandRange\$( compressed\$)

```   for i = 1 to ItemCount( compressed\$, ",")
item\$ = word\$( compressed\$, i, ",")
dash  = instr( item\$, "-", 2) 'dash that is not the first character, is a separator
if dash then
for k = val( left\$( item\$, dash - 1)) to val( mid\$( item\$, dash + 1))
ExpandRange\$ = ExpandRange\$ + str\$( k) + ","
next k
else
ExpandRange\$ = ExpandRange\$ + item\$ + ","
end if
next i
ExpandRange\$ = left\$( ExpandRange\$, len( ExpandRange\$) - 1)
```

end function

function ItemCount( list\$, separator\$)

```   while word\$(list\$, ItemCount + 1, separator\$) <> ""
ItemCount = ItemCount + 1
wend
```

end function</lang>

Output:
`-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20`

## Mathematica

<lang Mathematica>rangeexpand[ rng_ ] := Module[ { step1 }, step1 = StringSplit[StringReplacePart[rng,"S",StringPosition[ rng,DigitCharacter~~"-"] /. {x_,y_} -> {y,y}],","]; Flatten@ToExpression/@Quiet@StringReplace[step1,x__~~"S"~~y__->"Range["<>x<>","<>y<>"]"] ]</lang>

Example:
```rangeexpand["-6,-3--1,3-5,7-11,14,15,17-20"]
{-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20}```

## MUMPS

<lang MUMPS>RANGEXP(X) ;Integer range expansion

```NEW Y,I,J,X1,H SET Y=""
FOR I=1:1:\$LENGTH(X,",") DO
.S X1=\$PIECE(X,",",I) FOR  Q:\$EXTRACT(X1)'=" "  S X1=\$EXTRACT(X1,2,\$LENGTH(X1)) ;clean up leading spaces
.SET H=\$FIND(X1,"-")-1
.IF H=1 SET H=\$FIND(X1,"-",(H+1))-1 ;If the first value is negative ignore that "-"
.IF H<0 SET Y=\$SELECT(\$LENGTH(Y)=0:Y_X1,1:Y_","_X1)
.IF '(H<0) FOR J=+\$EXTRACT(X1,1,(H-1)):1:+\$EXTRACT(X1,(H+1),\$LENGTH(X1)) SET Y=\$SELECT(\$LENGTH(Y)=0:J,1:Y_","_J)
KILL I,J,X1,H
QUIT Y</lang>
```
Example:
```USER>SET U="-6,-3--1,3-5,7-11,14,15,17-20"

USER>WRITE \$\$RANGEXP^ROSETTA(U)
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20```

## OCaml

let range a b =

``` if b < a then invalid_arg "range";
let rec aux i acc =
if i = b then List.rev(i::acc)
else aux (succ i) (i::acc)
in
aux a []
```

let parse_piece s =

``` try Scanf.sscanf s "%d-%d" (fun a b -> range a b)
with _ -> [int_of_string s]
```

let range_expand rng =

``` let ps = Str.split (Str.regexp_string ",") rng in
List.flatten (List.map parse_piece ps)
```

let () =

``` let rng = "-6,-3--1,3-5,7-11,14,15,17-20" in
let exp = range_expand rng in
List.iter (Printf.printf " %d") exp;
print_newline()</lang>
```

## Oz

<lang oz>declare

``` fun {Expand RangeDesc}
{Flatten
{Map {ParseDesc RangeDesc}
ExpandRange}}
end
```
``` fun {ParseDesc Txt}
{Map {String.tokens Txt &,} ParseRange}
end
```
``` fun {ParseRange R}
if {Member &- R.2} then
First Second
in
{String.token R.2 &- ?First ?Second}
{String.toInt R.1|First}#{String.toInt Second}
else
Singleton = {String.toInt R}
in
Singleton#Singleton
end
end
```
``` fun {ExpandRange From#To}
{List.number From To 1}
end
```

in

``` {System.showInfo
{Value.toVirtualString {Expand "-6,-3--1,3-5,7-11,14,15,17-20"} 100 100}}</lang>
```
Sample output:

<lang oz>[~6 ~3 ~2 ~1 3 4 5 7 8 9 10 11 14 15 17 18 19 20]</lang>

## Perl

One-liner: <lang Perl>sub rangex {

```   map { /^(.*\d)-(.+)\$/ ? \$1..\$2 : \$_ } split /,/, shift
```

}

1. Test and display

print join(',', rangex('-6,-3--1,3-5,7-11,14,15,17-20')), "\n";</lang>

Output:
`-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20`

Alternative: <lang Perl>sub rangex {

```   (my \$range = shift) =~ s/(?<=\d)-/../g;
eval \$range;
```

}</lang>

## Perl 6

<lang Perl6>sub range-expansion (Str \$range-description) {

```   my \$range-pattern = rx/ ( '-'? \d+ ) '-' ( '-'? \d+) /;
my &expand = -> \$term { \$term ~~ \$range-pattern ?? +\$0..+\$1 !! \$term };
return \$range-description.split(',').map(&expand)
```

}

say range-expansion('-6,-3--1,3-5,7-11,14,15,17-20').join(', ');</lang>

Output:
`-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20`

## PHP

Translation of: Python

<lang PHP>function rangex(\$str) {

```   \$lst = array();
foreach (explode(',', \$str) as \$e) {
if (strpos(\$e, '-', 1) !== FALSE) {
list(\$a, \$b) = explode('-', substr(\$e, 1), 2);
\$lst = array_merge(\$lst, range(\$e[0] . \$a, \$b));
} else {
\$lst[] = (int) \$e;
}
}
return \$lst;
```

}</lang>

## PicoLisp

<lang PicoLisp>(de rangeexpand (Str)

```  (make
(for S (split (chop Str) ",")
(if (index "-" (cdr S))
(chain
(range
(format (tail (- -1 @) S)) ) )
(link (format S)) ) ) ) )</lang>
```
Output:
```: (rangeexpand "-6,-3--1,3-5,7-11,14,15,17-20")
-> (-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20)```

## PL/I

<lang PL/I>range_expansion:

```  procedure options (main);
```

get_number:

```  procedure (Number, c, eof);
declare number fixed binary (31), c character (1), eof bit (1) aligned;
declare neg fixed binary (1);
```
```  number = 0; eof = false;
do until (c ^= ' ');
get edit (c) (a(1));
end;
if c = '-' then do; get edit (c) (a(1)); neg = -1; end; else neg = 1;
do forever;
select (c);
when ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
number = number*10 + c;
when (',', '-') do; number = neg*number; return; end;
otherwise signal error;
end;
on endfile (sysin) go to exit;
get edit (c) (a(1));
end;
```

exit:

```  number = neg*number;
eof = true;
```

end get_Number;

```  declare c character, (i, range_start, range_end) fixed binary (31);
declare eof bit (1) aligned;
declare true bit (1) value ('1'b), false bit (1) value ('0'b);
declare delimiter character (1) initial (' ');
declare out file output;
```
```  open file (out) output title ('/out, type(text),recsize(80)');
do while (^eof);
call get_number(range_start, c, eof);
if c = '-' then /* we have a range */
do;
call get_number (range_end, c, eof);
do i = range_start to range_end;
put file (out) edit (delimiter, i) (a, f(3));
end;
end;
else
do;
put file (out) edit (delimiter, range_start) (a, f(3));
end;
delimiter = ',';
end;
```

end range_expansion;</lang>

Output:
```  -6, -3, -2, -1,  3,  4,  5,  7,  8,  9, 10, 11, 14, 15, 17, 18, 19, 20
```

## Prolog

Works with: SWI Prolog
Library: clpfd

The code uses three predicates extract_Range/2, study_Range/2 and pack_Range/2.
Every predicate works in both directions arg1 towards arg2 and arg2 towards arg1, so that Range expansion and Range extraction work with the same predicates but in reverse order. <lang Prolog>range_expand :- L = '-6,-3--1,3-5,7-11,14,15,17-20', writeln(L), atom_chars(L, LA), extract_Range(LA, R), maplist(study_Range, R, LR), pack_Range(LX, LR), writeln(LX).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % extract_Range(?In, ?Out) % In  : '-6,-3--1,3-5,7-11,14,15,17-20' % Out : [-6], [-3--1], [3-5],[7-11], [14],[15], [17-20] % extract_Range([], []).

extract_Range(X , [Range | Y1]) :- get_Range(X, U-U, Range, X1), extract_Range(X1, Y1).

get_Range([], Range-[], Range, []). get_Range([','|B], Range-[], Range, B) :- !.

get_Range([A | B], EC, Range, R) :- append_dl(EC, [A | U]-U, NEC), get_Range(B, NEC, Range, R).

append_dl(X-Y, Y-Z, X-Z).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % study Range(?In, ?Out) % In  : [-6] % Out : [-6,-6] % % In  : [-3--1] % Out : [-3, -1] % study_Range(Range1, [Deb, Deb]) :-

```      catch(number_chars(Deb, Range1), Deb, false).
```

study_Range(Range1, [Deb, Fin]) :-

```      append(A, ['-'|B], Range1),
A \= [],
number_chars(Deb, A),
number_chars(Fin, B).
```

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %

- use_module(library(clpfd)).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Pack Range(?In, ?Out) % In  : -6, % Out : [-6] % % In  : -3, -2,-1 % Out : [-3,-1] % pack_Range([],[]).

pack_Range([X|Rest],[[X | V]|Packed]):-

```   run(X,Rest, [X|V], RRest),
pack_Range(RRest,Packed).
```

run(Fin,[Other|RRest], [Deb, Fin],[Other|RRest]):- Fin #\= Deb, Fin #\= Deb + 1, Other #\= Fin+1.

run(Fin,[],[_Var, Fin],[]).

run(Var,[Var1|LRest],[Deb, Fin], RRest):- Fin #\= Deb, Fin #\= Deb + 1, Var1 #= Var + 1, run(Var1,LRest,[Deb, Fin], RRest).

run(Val,[Other|RRest], [Val, Val],[Other|RRest]).</lang>

Output:
``` ?- range_expand.
-6,-3--1,3-5,7-11,14,15,17-20
[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]
true```

## PureBasic

<lang PureBasic>Procedure rangeexpand(txt.s, List outputList())

``` Protected rangesCount = CountString(txt, ",") + 1
Protected subTxt.s, r, rangeMarker, rangeStart, rangeFinish, rangeIncrement, i

LastElement(outputList())
For r = 1 To rangesCount
subTxt = StringField(txt, r, ",")
rangeMarker = FindString(subTxt, "-", 2)
If rangeMarker
rangeStart = Val(Mid(subTxt, 1, rangeMarker - 1))
rangeFinish = Val(Mid(subTxt, rangeMarker + 1))

If rangeStart > rangeFinish
rangeIncrement = -1
Else
rangeIncrement = 1
EndIf

i = rangeStart - rangeIncrement
Repeat
i + rangeIncrement
Until i = rangeFinish
Else
EndIf
Next
```

EndProcedure

Procedure outputListValues(List values())

``` Print("[ ")
ForEach values()
Print(Str(values()) + " ")
Next
PrintN("]")
```

EndProcedure

If OpenConsole()

``` NewList values()
rangeexpand("-6,-3--1,3-5,7-11,14,15,17-20", values())
outputListValues(values())

Print(#CRLF\$ + #CRLF\$ + "Press ENTER to exit")
Input()
CloseConsole()
```

EndIf</lang>

Output:
`[ -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 ]`

## Python

<lang python>def rangeexpand(txt):

```   lst = []
for r in txt.split(','):
if '-' in r[1:]:
r0, r1 = r[1:].split('-', 1)
lst += range(int(r[0] + r0), int(r1) + 1)
else:
lst.append(int(r))
return lst
```

print(rangeexpand('-6,-3--1,3-5,7-11,14,15,17-20'))</lang> Another variant, using regular expressions to parse the ranges: <lang python>import re

def rangeexpand(txt):

```   lst = []
for rng in txt.split(','):
start,end = re.match('^(-?\d+)(?:-(-?\d+))?\$', rng).groups()
if end:
lst.extend(xrange(int(start),int(end)+1))
else:
lst.append(int(start))
return lst</lang>
```
Output:
`[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]`

## REXX

<lang rexx>/*REXX program to expand a range of integers into a list. */

old='-6,-3--1,3-5,7-11,14,15,17-20' /*original list of nums/ranges. */

say 'old list='old /*show old list of nums/ranges. */ a=translate(old,,',') /*translate commas to blanks */ new= /*new list of numbers (so far). */

``` do j=1                               /*process each number or range.  */
y=                                 /*nullify the output number(s).  */
parse var a x a; if x== then leave /*get next num/range. Null? Done.*/
minus=pos('-',x,2)                   /*find location of a dash (maybe)*/
if minus\==0 then do                 /*if found then process range.   */
do k=left(x,minus-1) to substr(x,minus+1)
y=y k            /*build one integer at a time.   */
end
x=               /*nullify X, it's still a range. */
end
new=new x y                          /*append them to the new list.   */
end
```

new=space(new) /*remove extraneous blanks. */ say 'new list='new /*show the new list of numbers. */</lang>

Output:
```old list=-6,-3--1,3-5,7-11,14,15,17-20
new list=-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
```

## Ruby

<lang ruby>def range_expand(rng)

``` rng.split(',').collect do |part|
if part =~ /^(-?\d+)-(-?\d+)\$/
(\$1.to_i .. \$2.to_i).to_a
else
Integer(part)
end
end.flatten
```

end

p range_expand('-6,-3--1,3-5,7-11,14,15,17-20')</lang>

Output:
`[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]`

## Scala

<lang ruby>def rangex(str: String): Seq[Int] =

``` str split "," flatMap { (s) =>
val r = """(-?\d+)(?:-(-?\d+))?""".r
val r(a,b) = s
if (b == null) Seq(a.toInt) else a.toInt to b.toInt
}</lang>
```

## Scheme

<lang scheme>(define split

``` (lambda (str char skip count)
(let ((len (string-length str)))
(let loop ((index skip)
(last-index 0)
(result '()))
(if (= index len)
(reverse (cons (substring str last-index) result))
(if (eq? char (string-ref str index))
(loop (if (= count (+ 2 (length result)))
len
(+ index 1))
(+ index 1)
(cons char (cons (substring str last-index index)
result)))
(loop (+ index 1)
last-index
result)))))))
```

(define range-expand

``` (lambda (str)
(for-each
(lambda (token)
(if (char? token)
(display token)
(let ((range (split token #\- 1 2)))
(if (null? (cdr range))
(display (car range))
(do ((count (string->number (list-ref range 0)) (+ 1 count))
(high (string->number (list-ref range 2))))
((= count high) (display high))
(display count)
(display ","))))))
(split str #\, 0 0))
(newline)))</lang>
```
Output:
```(range-expand "-6,-3--1,3-5,7-11,14,15,17-20")
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
```

## Seed7

The library scanstri.s7i defines the function getInteger to extract substrings with integer literals (optional sign followed by a sequence of digits) from a string. The integer literals are converted to the type integer with the parse operator. <lang seed7>\$ include "seed7_05.s7i";

``` include "scanstri.s7i";
```

const func array integer: rangeExpansion (in var string: rangeStri) is func

``` result
var array integer: numbers is 0 times 0;
local
var integer: number is 0;
begin
while rangeStri <> "" do
number := integer parse getInteger(rangeStri);
numbers &:= number;
if startsWith(rangeStri, "-") then
rangeStri := rangeStri[2 ..];
for number range succ(number) to integer parse getInteger(rangeStri) do
numbers &:= number;
end for;
end if;
if startsWith(rangeStri, ",") then
rangeStri := rangeStri[2 ..];
elsif rangeStri <> "" then
raise RANGE_ERROR;
end if;
end while;
end func;
```

const proc: main is func

``` local
var integer: number is 0;
begin
for number range rangeExpansion("-6,-3--1,3-5,7-11,14,15,17-20") do
write(number <& " ");
end for;
writeln;
end func;</lang>
```
Output:
```-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
```

## SNOBOL4

<lang SNOBOL4>* # Return range n1 .. n2

```       define('range(n1,n2)') :(range_end)
```

range range = range n1 ','; n1 = lt(n1,n2) n1 + 1 :s(range)

```       range rtab(1) . range :(return)
```

range_end

```       define('rangex(range)d1,d2')
num = ('-' | ) span('0123456789') :(rangex_end)
```

rangex range num . d1 '-' num . d2 = range(d1,d2) :s(rangex)

```       rangex = range :(return)
```

rangex_end

• # Test and display
```       output = rangex('-6,-3--1,3-5,7-11,14,15,17-20')
```

end</lang>

Output:
`-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20`

## Tcl

<lang tcl>proc rangeExpand desc {

```   set result {}
foreach term [split \$desc ","] {
```

set count [scan \$term %d-%d from to] if {\$count == 1} { lappend result \$from } elseif {\$count == 2} { for {set i \$from} {\$i <= \$to} {incr i} {lappend result \$i} }

```   }
return \$result
```

}

puts [rangeExpand "-6,-3--1,3-5,7-11,14,15,17-20"]</lang>

Output:
`-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20`

## TUSCRIPT

<lang tuscript>\$\$ MODE TUSCRIPT rangednrs="-6,-3--1,3-5,7-11,14,15,17-20" expandnrs=SPLIT (rangednrs,":,:")

LOOP/CLEAR r=expandnrs

```test=STRINGS (r,":><-><<>>/:")
sz_test=SIZE (test)
IF (sz_test==1) THEN
expandnrs=APPEND (expandnrs,r)
ELSE
r=SPLIT (r,"::<|->/::-:",beg,end)
expandnrs=APPEND (expandnrs,beg)
LOOP/CLEAR next=beg,end
next=next+1
expandnrs=APPEND (expandnrs,next)
IF (next==end) EXIT
ENDLOOP
ENDIF
```

ENDLOOP expandnrs= JOIN (expandnrs,",")

PRINT expandnrs</lang>

Output:
```-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
```

## Ursala

<lang Ursala>#import std

1. import int

rex = sep`,; zrange+*= %zp~~htttPzztPQhQXbiNC+ rlc ~&r~=`-

1. cast %zL

t = rex '-6,-3--1,3-5,7-11,14,15,17-20'</lang>

Output:
`<-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20>`

## VBA

<lang VBA>Public Function RangeExpand(AString as string) ' return a list with the numbers expressed in AString Dim Splits() As String Dim List() As Integer Dim count As Integer

count = -1 'to start a zero-based List() array ' first split it using comma as delimiter Splits = Split(AString, ",") ' process all fragments For Each fragment In Splits

``` 'is there a "-" in it (do not consider first character)?
P = InStr(2, fragment, "-")
If P > 0 Then 'yes, so it's a range: find start and end numbers
nstart = Val(left\$(fragment, P - 1))
nend = Val(Mid\$(fragment, P + 1))
j = count
count = count + (nend - nstart + 1)
'add numbers in range to List
ReDim Preserve List(count)
For i = nstart To nend
j = j + 1
List(j) = i
Next
Else
'not a range, add a single number
count = count + 1
ReDim Preserve List(count)
List(count) = Val(fragment)
End If
```

Next RangeExpand = List End Function

Public Sub RangeExpandTest() 'test function RangeExpand Dim X As Variant

X = RangeExpand("-6,-3--1,3-5,7-11,14,15,17-20") 'print X Debug.Print "Result:" For Each el In X

``` Debug.Print el;
```

Next Debug.Print End Sub</lang>

Output:
```RangeExpandTest
Result:
-6 -3 -2 -1  3  4  5  7  8  9  10  11  14  15  17  18  19  20
```

## XPL0

<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations string 0; \use zero-terminated strings, instead of MSb char Str; int Char, Inx;

proc GetCh; \Get character from Str [Char:= Str(Inx); Inx:= Inx+1; ]; \GetCh

func GetNum; \Get number from Str and return its value int Neg, Num; [Neg:= false; if Char = ^- then [Neg:= true; GetCh]; Num:= 0; while Char>=^0 & Char<=^9 do

```       [Num:= Num*10 + Char-^0;
GetCh;
];
```

return if Neg then -Num else Num; ]; \GetNum

int I, N0, N1; [Str:= "-6,-3--1,3-5,7-11,14,15,17-20"; Inx:= 0; GetCh; \one character look ahead loop [N0:= GetNum;

```       IntOut(0,N0);
case Char of
^,:   [GetCh;  ChOut(0,^,)];
^-:   [GetCh;
N1:= GetNum;
for I:= N0+1 to N1 do   \expand range
[ChOut(0,^,);  IntOut(0,I)];
if Char=^, then [GetCh;  ChOut(0,^,)] else quit]
other   quit;                   \must be 0 string terminator
];
```

CrLf(0); ]</lang>

Output:

```-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
```