Range expansion: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Groovy}}: new solution)
m (<lang> needs a language)
Line 1: Line 1:
{{task}}
{{task}}{{:Range extraction/Format}}
{{:Range extraction/Format}}


'''The task'''<br>
;The task
Expand the range description:
Expand the range description:
: -6,-3--1,3-5,7-11,14,15,17-20
: -6,-3--1,3-5,7-11,14,15,17-20
Line 11: Line 10:
=={{header|Ada}}==
=={{header|Ada}}==
The function Expand takes a string and returns a corresponding array of integers. Upon syntax errors Constraint_Error is propagated:
The function Expand takes a string and returns a corresponding array of integers. Upon syntax errors Constraint_Error is propagated:
<lang Ada>
<lang Ada>with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Range_Expansion is
procedure Test_Range_Expansion is
type Sequence is array (Positive range <>) of Integer;
type Sequence is array (Positive range <>) of Integer;
Line 77: Line 75:
begin
begin
Put (Expand ("-6,-3--1,3-5,7-11,14,15,17-20"));
Put (Expand ("-6,-3--1,3-5,7-11,14,15,17-20"));
end Test_Range_Expansion;
end Test_Range_Expansion;</lang>
{{out}}
</lang>
Sample output:
<pre>
<pre>
-6,-3,-2,-1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
-6,-3,-2,-1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
</pre>
</pre>

=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
{{incorrect|ALGOL 68|The task example was modified after discussion in the talk page.}}
{{incorrect|ALGOL 68|The task example was modified after discussion in the talk page.}}

{{works with|ALGOL 68|Revision 1 - no extensions to language used}}
{{works with|ALGOL 68|Revision 1 - no extensions to language used}}

{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}}
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}}

{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d]}}
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d]}}

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


Line 131: Line 125:
print((range expand(list), new line))
print((range expand(list), new line))
)</lang>
)</lang>
{{out}}
Output:
<pre>
<pre>
-6 -3 -2 -1 +3 +4 +5 +7 +8 +9 +10 +11 +14 +15 +17 +18 +19 +20
-6 -3 -2 -1 +3 +4 +5 +7 +8 +9 +10 +11 +14 +15 +17 +18 +19 +20
Line 226: Line 220:


return 0;
return 0;
}</lang>
}</lang>output<lang>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
{{out}}
<pre>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
Ok
Ok
-6 -5 -4 -3 -2 -1 0 1 2 3
-6 -5 -4 -3 -2 -1 0 1 2 3
Syntax error at --1,3-5,7-11,14,15,17-20</lang>
Syntax error at --1,3-5,7-11,14,15,17-20</pre>


=={{header|C sharp}}==
=={{header|C sharp|C#}}==
{{works with|C sharp|3.0}}
{{works with|C sharp|3.0}}

<lang csharp>using System;
<lang csharp>using System;
using System.Collections.Generic;
using System.Collections.Generic;
Line 266: Line 261:


=={{header|C++}}==
=={{header|C++}}==
<lang cpp>
<lang cpp>#include <iostream>
#include <iostream>
#include <sstream>
#include <sstream>
#include <iterator>
#include <iterator>
Line 340: Line 334:
else
else
std::cout << "an error occured.";
std::cout << "an error occured.";
}</lang>
}
{{out}}
</lang>
Output:
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20


Line 370: Line 363:


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


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
Line 396: Line 388:


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


=={{header|D}}==
=={{header|D}}==
Line 417: Line 408:
writeln(rangeExpand("-6,-3--1,3-5,7-11,14,15,17-20"));
writeln(rangeExpand("-6,-3--1,3-5,7-11,14,15,17-20"));
}</lang>
}</lang>
{{out}}
Output:
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>


Line 444: Line 435:


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

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

=={{header|Go}}==
=={{header|Go}}==
A version rather strict with input
A version rather strict with input
Line 525: Line 516:
Eval.me('['+compressed.replaceAll(~/(\d)-/, '$1..')+']').flatten().toString()[1..-2]
Eval.me('['+compressed.replaceAll(~/(\d)-/, '$1..')+']').flatten().toString()[1..-2]
}</lang>
}</lang>

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

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


=={{header|Haskell}}==
=={{header|Haskell}}==

Given either of the below implementations of <code>expandRange</code>:
Given either of the below implementations of <code>expandRange</code>:

<lang haskell>> expandRange "-6,-3--1,3-5,7-11,14,15,17-20"
<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>
[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]</lang>

===With conventional list processing===
===With conventional list processing===

<lang haskell>expandRange :: String -> [Int]
<lang haskell>expandRange :: String -> [Int]
expandRange = concatMap f . split ','
expandRange = concatMap f . split ','
Line 552: Line 537:
split delim l = a : split delim (dropWhile (== delim) b)
split delim l = a : split delim (dropWhile (== delim) b)
where (a, b) = break (== delim) l</lang>
where (a, b) = break (== delim) l</lang>

===With a parser===
===With a parser===

<lang haskell>import Control.Monad
<lang haskell>import Control.Monad
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec
Line 598: Line 581:
return s || "]"
return s || "]"
end</lang>
end</lang>
{{out}}

Sample output:
<pre>Input string := -6,-3--1,3-5,7-11,14,15,17-20
<pre>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 ]</pre>
Expanded list := [ -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 ]</pre>
Line 610: Line 592:
lumps=:<@(num`([:to num;._1@,~&'-')@.('-'&e.));._1
lumps=:<@(num`([:to num;._1@,~&'-')@.('-'&e.));._1
rngexp=: ;@lumps@normaliz</lang>
rngexp=: ;@lumps@normaliz</lang>
{{out|Example}}

Example:
<lang j> rngexp '-6,-3--1,3-5,7-11,14,15,17-20'
<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>
_6 _3 _2 _1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</lang>
Line 619: Line 600:
import java.util.regex.*;
import java.util.regex.*;


class Range implements Enumeration
class Range implements Enumeration {
{
private int clower, cupper;
private int clower, cupper;
private int value;
private int value;
Line 639: Line 619:


public Object nextElement() throws NoSuchElementException {
public Object nextElement() throws NoSuchElementException {
if ( ! hasMoreElements() ) throw new NoSuchElementException();
if (!hasMoreElements())
throw new NoSuchElementException();
if ( inrange && (value >= clower && value <= cupper) ) {
if (inrange && (value >= clower && value <= cupper)) {
value++;
value++;
return value-1;
return value-1;
}
}
if ( inrange ) inrange = false;
inrange = false;
String n = ps.next();
String n = ps.next();
if ( n.matches("[+-]?\\d+-[+-]?\\d+") ) {
if (n.matches("[+-]?\\d+-[+-]?\\d+")) {
Scanner ls = new Scanner(n);
Scanner ls = new Scanner(n);
ls.findInLine("([+-]?\\d+)-([+-]?\\d+)");
ls.findInLine("([+-]?\\d+)-([+-]?\\d+)");
Line 661: Line 642:
public void reset() {
public void reset() {
if ( ps != null) ps.close();
if (ps != null)
ps.close();
ps = new Scanner(ss).useDelimiter(del);
ps = new Scanner(ss).useDelimiter(del);
inrange = false;
inrange = false;
Line 672: Line 654:
}
}


class rangexp
class rangexp {
{
public static void main(String[] args) {
public static void main(String[] args) {
Range r = new Range("-6,-3--1,3-5,7-11,14,15,17-20");
Range r = new Range("-6,-3--1,3-5,7-11,14,15,17-20");
while ( r.hasMoreElements() ) {
while (r.hasMoreElements()) {
System.out.print(r.nextElement() + " ");
System.out.print(r.nextElement() + " ");
}
}
Line 689: Line 670:
expd: {,/@[x;&2=#:'x;{(*x)+!1+,/-':x}]}
expd: {,/@[x;&2=#:'x;{(*x)+!1+,/-':x}]}
rnge: {expd@conv grp x}</lang>
rnge: {expd@conv grp x}</lang>
{{out|Example}}

'''Example:'''

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


=={{header|Liberty BASIC}}==
=={{header|Liberty BASIC}}==
<lang lb>print ExpandRange$( "-6,-3--1,3-5,7-11,14,15,17-20")
<lang lb>
print ExpandRange$( "-6,-3--1,3-5,7-11,14,15,17-20")
end
end


Line 719: Line 697:
ItemCount = ItemCount + 1
ItemCount = ItemCount + 1
wend
wend
end function
end function</lang>
{{out}}
</lang>
Sample output:- -6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>


=={{header|Mathematica}}==
=={{header|Mathematica}}==
Line 727: Line 705:
step1 = StringSplit[StringReplacePart[rng,"S",StringPosition[ rng,DigitCharacter~~"-"] /. {x_,y_} -> {y,y}],","];
step1 = StringSplit[StringReplacePart[rng,"S",StringPosition[ rng,DigitCharacter~~"-"] /. {x_,y_} -> {y,y}],","];
Flatten@ToExpression/@Quiet@StringReplace[step1,x__~~"S"~~y__->"Range["<>x<>","<>y<>"]"] ]</lang>
Flatten@ToExpression/@Quiet@StringReplace[step1,x__~~"S"~~y__->"Range["<>x<>","<>y<>"]"] ]</lang>
{{out|Example}}

<pre>rangeexpand["-6,-3--1,3-5,7-11,14,15,17-20"]
<pre>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}</pre>
{-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20}</pre>


=={{header|MUMPS}}==
=={{header|MUMPS}}==
<lang MUMPS>
<lang MUMPS>RANGEXP(X) ;Integer range expansion
RANGEXP(X) ;Integer range expansion
NEW Y,I,J,X1,H SET Y=""
NEW Y,I,J,X1,H SET Y=""
FOR I=1:1:$LENGTH(X,",") DO
FOR I=1:1:$LENGTH(X,",") DO
Line 743: Line 720:
KILL I,J,X1,H
KILL I,J,X1,H
QUIT Y</lang>
QUIT Y</lang>
Example:
{{out|Example}}
<pre>USER>SET U="-6,-3--1,3-5,7-11,14,15,17-20"
<pre>USER>SET U="-6,-3--1,3-5,7-11,14,15,17-20"


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

Sample output (in Oz list syntax):
<lang oz>[~6 ~3 ~2 ~1 3 4 5 7 8 9 10 11 14 15 17 18 19 20]</lang>
<lang oz>[~6 ~3 ~2 ~1 3 4 5 7 8 9 10 11 14 15 17 18 19 20]</lang>


=={{header|Perl}}==
=={{header|Perl}}==

One-liner:
One-liner:
<lang Perl>sub rangex {
<lang Perl>sub rangex {
Line 818: Line 793:
# Test and display
# Test and display
print join(',', rangex('-6,-3--1,3-5,7-11,14,15,17-20')), "\n";</lang>
print join(',', rangex('-6,-3--1,3-5,7-11,14,15,17-20')), "\n";</lang>
{{out}}

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

Alternative:
Alternative:
<lang Perl>sub rangex {
<lang Perl>sub rangex {
Line 829: Line 802:


=={{header|Perl 6}}==
=={{header|Perl 6}}==

<lang Perl6>sub range-expansion (Str $range-description) {
<lang Perl6>sub range-expansion (Str $range-description) {
my $range-pattern = rx/ ( '-'? \d+ ) '-' ( '-'? \d+) /;
my $range-pattern = rx/ ( '-'? \d+ ) '-' ( '-'? \d+) /;
Line 837: Line 809:


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

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


=={{header|PHP}}==
=={{header|PHP}}==
{{trans|Python}}

Based on Python version.

<lang PHP>function rangex($str) {
<lang PHP>function rangex($str) {
$lst = array();
$lst = array();
Line 868: Line 837:
(format (tail (- -1 @) S)) ) )
(format (tail (- -1 @) S)) ) )
(link (format S)) ) ) ) )</lang>
(link (format S)) ) ) ) )</lang>
{{out}}
Output:
<pre>: (rangeexpand "-6,-3--1,3-5,7-11,14,15,17-20")
<pre>: (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)</pre>
-> (-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20)</pre>


=={{header|PL/I}}==
=={{header|PL/I}}==
<lang PL/I>
<lang PL/I>range_expansion:
range_expansion:
procedure options (main);
procedure options (main);


Line 924: Line 892:
delimiter = ',';
delimiter = ',';
end;
end;
end range_expansion;
end range_expansion;</lang>
{{out}}
</lang>
<pre>
OUTPUT
<lang>
-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
</lang>
</pre>


=={{header|Prolog}}==
=={{header|Prolog}}==
Works with SWI-Prolog and library clpfd.<BR>
{{Works with|SWI Prolog}}
{{libheader|clpfd}}
The code uses three predicates '''extract_Range/2''', '''study_Range/2''' and '''pack_Range/2'''.<BR>
The code uses three predicates '''extract_Range/2''', '''study_Range/2''' and '''pack_Range/2'''.<BR>
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.
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.
Line 950: Line 918:
%
%
extract_Range([], []).
extract_Range([], []).



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




get_Range([], Range-[], Range, []).
get_Range([], Range-[], Range, []).
Line 1,003: Line 968:
run(X,Rest, [X|V], RRest),
run(X,Rest, [X|V], RRest),
pack_Range(RRest,Packed).
pack_Range(RRest,Packed).





Line 1,019: Line 983:
run(Var1,LRest,[Deb, Fin], RRest).
run(Var1,LRest,[Deb, Fin], RRest).


run(Val,[Other|RRest], [Val, Val],[Other|RRest]).
run(Val,[Other|RRest], [Val, Val],[Other|RRest]).</lang>
{{out}}
</lang>
Output :
<pre> ?- range_expand.
<pre> ?- range_expand.
-6,-3--1,3-5,7-11,14,15,17-20
-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]
[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]
true</pre>
true</pre>




=={{header|PureBasic}}==
=={{header|PureBasic}}==
Line 1,076: Line 1,037:
CloseConsole()
CloseConsole()
EndIf</lang>
EndIf</lang>
{{out}}
Sample output:
<pre>[ -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 ]</pre>
<pre>[ -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 ]</pre>


Line 1,091: Line 1,052:


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

Another variant, using [[regular expressions]] to parse the ranges:
Another variant, using [[regular expressions]] to parse the ranges:

<lang python>import re
<lang python>import re


Line 1,105: Line 1,064:
lst.append(int(start))
lst.append(int(start))
return lst</lang>
return lst</lang>
{{out}}

'''Sample output'''
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>


=={{header|REXX}}==
=={{header|REXX}}==
<lang rexx>/*REXX program to expand a range of integers into a list. */
<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. */
old='-6,-3--1,3-5,7-11,14,15,17-20' /*original list of nums/ranges. */
Line 1,133: Line 1,090:


new=space(new) /*remove extraneous blanks. */
new=space(new) /*remove extraneous blanks. */
say 'new list='new /*show the new list of numbers. */
say 'new list='new /*show the new list of numbers. */</lang>
{{out}}
</lang>
<pre>
Output:
<pre style="height:30ex;overflow:scroll">
old list=-6,-3--1,3-5,7-11,14,15,17-20
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
new list=-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
Line 1,153: Line 1,109:


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

output:

<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>


Line 1,164: Line 1,118:
val r(a,b) = s
val r(a,b) = s
if (b == null) Seq(a.toInt) else a.toInt to b.toInt
if (b == null) Seq(a.toInt) else a.toInt to b.toInt
}
}</lang>
</lang>


=={{header|Scheme}}==
=={{header|Scheme}}==
<lang scheme>
<lang scheme>(define split
(define split
(lambda (str char skip count)
(lambda (str char skip count)
(let ((len (string-length str)))
(let ((len (string-length str)))
Line 1,203: Line 1,155:
(display ","))))))
(display ","))))))
(split str #\, 0 0))
(split str #\, 0 0))
(newline)))
(newline)))</lang>
{{out}}
</lang>

<pre>
<pre>
(range-expand "-6,-3--1,3-5,7-11,14,15,17-20")
(range-expand "-6,-3--1,3-5,7-11,14,15,17-20")
Line 1,212: Line 1,163:


=={{header|Seed7}}==
=={{header|Seed7}}==
The library [http://seed7.sourceforge.net/libraries/scanstri.htm scanstri.s7i]
The library [http://seed7.sourceforge.net/libraries/scanstri.htm scanstri.s7i] defines the function [http://seed7.sourceforge.net/libraries/scanstri.htm#getInteger%28inout_string%29 getInteger] to extract substrings with integer literals (optional sign followed by a sequence of digits) from a string.
defines the function [http://seed7.sourceforge.net/libraries/scanstri.htm#getInteger%28inout_string%29 getInteger]
The integer literals are converted to the type [http://seed7.sourceforge.net/libraries/integer.htm integer] with the [http://seed7.sourceforge.net/libraries/integer.htm#%28attr_integer%29parse%28in_string%29 parse] operator.
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 [http://seed7.sourceforge.net/libraries/integer.htm integer]
with the [http://seed7.sourceforge.net/libraries/integer.htm#%28attr_integer%29parse%28in_string%29 parse] operator.

<lang seed7>$ include "seed7_05.s7i";
<lang seed7>$ include "seed7_05.s7i";
include "scanstri.s7i";
include "scanstri.s7i";
Line 1,253: Line 1,200:
writeln;
writeln;
end func;</lang>
end func;</lang>
{{out}}

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


=={{header|SNOBOL4}}==
=={{header|SNOBOL4}}==

<lang SNOBOL4>* # Return range n1 .. n2
<lang SNOBOL4>* # Return range n1 .. n2
define('range(n1,n2)') :(range_end)
define('range(n1,n2)') :(range_end)
Line 1,276: Line 1,221:
output = rangex('-6,-3--1,3-5,7-11,14,15,17-20')
output = rangex('-6,-3--1,3-5,7-11,14,15,17-20')
end</lang>
end</lang>
{{out}}

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


Line 1,295: Line 1,239:


puts [rangeExpand "-6,-3--1,3-5,7-11,14,15,17-20"]</lang>
puts [rangeExpand "-6,-3--1,3-5,7-11,14,15,17-20"]</lang>
{{out}}
Output:
<pre>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</pre>
<pre>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</pre>

=={{header|TUSCRIPT}}==
=={{header|TUSCRIPT}}==
<lang tuscript>
<lang tuscript>$$ MODE TUSCRIPT
$$ MODE TUSCRIPT
rangednrs="-6,-3--1,3-5,7-11,14,15,17-20"
rangednrs="-6,-3--1,3-5,7-11,14,15,17-20"
expandnrs=SPLIT (rangednrs,":,:")
expandnrs=SPLIT (rangednrs,":,:")
Line 1,320: Line 1,264:
expandnrs= JOIN (expandnrs,",")
expandnrs= JOIN (expandnrs,",")


PRINT expandnrs
PRINT expandnrs</lang>
{{out}}
</lang>
Output:
<pre>
<pre>
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
Line 1,328: Line 1,271:


=={{header|Ursala}}==
=={{header|Ursala}}==

<lang Ursala>#import std
<lang Ursala>#import std
#import int
#import int
Line 1,337: Line 1,279:


t = rex '-6,-3--1,3-5,7-11,14,15,17-20'</lang>
t = rex '-6,-3--1,3-5,7-11,14,15,17-20'</lang>
{{out}}
output: <pre><-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20></pre>
<pre><-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20></pre>


=={{header|VBA}}==
=={{header|VBA}}==
<lang VBA>Public Function RangeExpand(AString as string)
<lang VBA>
Public Function RangeExpand(AString as string)
' return a list with the numbers expressed in AString
' return a list with the numbers expressed in AString
Dim Splits() As String
Dim Splits() As String
Line 1,386: Line 1,328:
Next
Next
Debug.Print
Debug.Print
End Sub
End Sub</lang>
{{out}}
</lang>

Output:
<pre>
<pre>
RangeExpandTest
RangeExpandTest

Revision as of 10:16, 21 February 2012

Task
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).

The task

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

Ada

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>

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 */

void add_number(int x); int add_range(int x, int y);

  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)
           {
               values.Add(m.Value);
               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;
 // the list always has to start with a 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)

(let [[r0 r1] (split s \-)] (range (read-string r0) (inc (read-string r1)))) (list (read-string (str s))))))

(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; txt.split(",")) {
       const m = array(r.match(r"^(-?\d+)(-?(-?\d+))?$").captures);
       result ~= m[2].empty ? [to!int(m[1])] :
                 array(iota(to!int(m[1]), to!int(m[3])+1));
   }
   return result;

}

void main() {

   writeln(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]

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

Ad Hoc Solution:

  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

Haskell

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]
                      | otherwise     = [read str]
           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

<lang haskell>import Control.Monad import Text.ParserCombinators.Parsec

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

<lang ocaml>#load "str.cma"

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 (head @ S))
                 (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
       AddElement(outputList()): outputList() = i
     Until i = rangeFinish
   Else
     AddElement(outputList()): outputList() = Val(subTxt)
   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