Range expansion: Difference between revisions

added RPL
(added RPL)
(112 intermediate revisions by 42 users not shown)
Line 1:
{{task}}{{:Range extraction/Format}}
{{:Range extraction/Format}}
 
 
;The task
;Task:
Expand the range description:
: <big> -6,-3--1,3-5,7-11,14,15,17-20 </big>
 
<small>Note that the second element above,
is the '''range from minus 3 to ''minus'' 1'''. </small>
 
 
C.f. [[Range extraction]]
;Related task:
* &nbsp; [[Range extraction]]
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
<syntaxhighlight lang="11l">F rangeexpand(txt)
[Int] lst
L(r) txt.split(‘,’)
I ‘-’ C r[1..]
V rr = r[1..].split(‘-’, 2)
lst [+]= Int(r[0]‘’rr[0]) .. Int(rr[1])
E
lst.append(Int(r))
R lst
 
print(rangeexpand(‘-6,-3--1,3-5,7-11,14,15,17-20’))</syntaxhighlight>
 
=={{header|8th}}==
<syntaxhighlight lang="forth">\ Given a low and high limit, create an array containing the numbers in the
\ range, inclusive:
: n:gen-range \ low hi -- a
\ make sure they are in order:
2dup n:> if swap then
\ fill the array with the values:
[] ' a:push
2swap loop ;
 
\ Take a string, either "X" or "X-Y", and correctly return either a number (if
\ "X") or an array of numbers (if "X-Y"):
: n:expand-one \ s -- n | a[n,..m]
\ First see if we can parse a number. This works in the "X" case:
dup >n null? if
\ Failed >n because it's (possibly) "X-Y"
drop
\ not a valid number, might be a range
\ We'll use a capturing regex to handle the different cases correctly:
/(-?[0-9]+)-(-?[0-9]+)/ tuck r:match
 
\ If the regex matches three (the whole string, plus the two captured
\ expressions) then it's a valid "X-Y":
3 n:= if
1 r:@ >n swap 2 r:@ >n nip
\ generate the range:
n:gen-range
else
\ The regex didn't match, so we got garbage. Therefore, return a 'null':
drop null
then
else
\ It was a "X", just drop the original string:
nip
then
;
 
\ Take an array (possibly) containing other arrays, and flatten any contained
\ arrays so the result is a simple array:
: a:flatten \ a1 -- a2
[] >r
(
nip
array? if
a:flatten r> swap a:+ >r
else
r> swap a:push >r
then
) a:each drop r> ;
 
\ Take a comma-delimited string of ranges, and expand it into an array of
\ numbers:
: n:range-expand \ str -- a
"," s:/
' n:expand-one a:map
a:flatten ;
 
\ Process a list:
"-6,-3--1,3-5,7-11,14,15,17-20"
n:range-expand
\ print the expanded list:
. cr bye</syntaxhighlight>
{{out}}
<pre>
[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]
</pre>
 
=={{header|Action!}}==
<syntaxhighlight lang="action!">BYTE FUNC Find(CHAR ARRAY text CHAR c BYTE start)
BYTE i
 
i=start
WHILE i<=text(0)
DO
IF text(i)=c THEN
RETURN (i)
FI
i==+1
OD
RETURN (0)
 
PROC ProcessItem(CHAR ARRAY text INT ARRAY res INT POINTER size)
BYTE pos
INT start,end,i
CHAR ARRAY tmp(200)
 
pos=Find(text,'-,2)
IF pos=0 THEN
res(size^)=ValI(text)
size^==+1
ELSE
SCopyS(tmp,text,1,pos-1)
start=ValI(tmp)
SCopyS(tmp,text,pos+1,text(0))
end=ValI(tmp)
FOR i=start TO end
DO
res(size^)=i
size^==+1
OD
FI
RETURN
 
PROC RangeExtraction(CHAR ARRAY text INT ARRAY res INT POINTER size)
BYTE i,pos
CHAR ARRAY tmp(200)
 
i=1 size^=0
WHILE i<=text(0)
DO
pos=Find(text,',,i)
IF pos=0 THEN
SCopyS(tmp,text,i,text(0))
i=text(0)+1
ELSE
SCopyS(tmp,text,i,pos-1)
i=pos+1
FI
ProcessItem(tmp,res,size)
OD
RETURN
 
PROC PrintArray(INT ARRAY a INT size)
INT i
 
Put('[)
FOR i=0 TO size-1
DO
IF i>0 THEN Put(' ) FI
PrintI(a(i))
OD
Put(']) PutE()
RETURN
 
PROC Main()
INT ARRAY res(100)
INT size
RangeExtraction("-6,-3--1,3-5,7-11,14,15,17-20",res,@size)
PrintArray(res,size)
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Range_expansion.png Screenshot from Atari 8-bit computer]
<pre>
[-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20]
</pre>
 
=={{header|Ada}}==
The function Expand takes a string and returns a corresponding array of integers.
Upon syntax errors Constraint_Error is propagated:
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Range_Expansion is
type Sequence is array (Positive range <>) of Integer;
Line 77 ⟶ 243:
begin
Put (Expand ("-6,-3--1,3-5,7-11,14,15,17-20"));
end Test_Range_Expansion;</langsyntaxhighlight>
{{out}}
<pre>
-6,-3,-2,-1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
</pre>
 
=={{header|Aime}}==
{{incorrect|Aime|Needs "a comma separated list" without the trailing comma}}
<syntaxhighlight lang="aime">list l;
 
file().b_affix("-6,-3--1,3-5,7-11,14,15,17-20").news(l, 0, 0, ",");
for (, text s in l) {
integer a, b, p;
 
p = b_frame(s, '-');
if (p < 1) {
o_(s, ",");
} else {
p -= s[p - 1] == '-' ? 1 : 0;
a = s.cut(0, p).atoi;
b = s.erase(0, p).atoi;
do {
o_(a, ",");
} while ((a += 1) <= b);
}
}
 
o_("\n");</syntaxhighlight>
or:
<syntaxhighlight lang="aime">integer p;
list l;
 
file().b_affix("-6,-3--1,3-5,7-11,14,15,17-20").news(l, 0, 0, ",");
for (, text s in l) {
if ((p = b_frame(s, '-')) < 1) {
o_(s, ",");
} else {
p -= s[p - 1] == '-' ? 1 : 0;
call_s(o_, 0, s.cut(0, p).atoi, s.erase(0, p).atoi + 1, 1, ",");
}
}
 
o_("\n");</syntaxhighlight>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20,</pre>
 
=={{header|ALGOL 68}}==
Line 87 ⟶ 293:
{{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] - string parsing and formatting code tested with 2.6.win32}}
{{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]}}
<langsyntaxhighlight lang="algol68">MODE YIELDINT = PROC(INT)VOID;
 
MODE RANGE = STRUCT(INT lwb, upb);
Line 238 ⟶ 444:
OP TOSTRING = ( []INT values )STRING:
BEGIN
 
# converts an integer to a string #
OP TOSTRING = ( INT value )STRING:
BEGIN
STRING result := "";
INT n := ABS value;
 
WHILE
REPR ( ( n MOD 10 ) + ABS "0" ) PLUSTO result;
n OVERAB 10;
n > 0
DO
SKIP
OD;
 
# RESULT #
IF value < 0 THEN "-" ELSE "" FI + result
END; # TOSTRING #
 
 
STRING result := "";
STRING separator := "";
Line 263 ⟶ 450:
FOR pos FROM LWB values TO UPB values
DO
result +:= ( separator + TOSTRINGwhole( values[ pos ], 0 ) );
separator := ","
OD;
Line 270 ⟶ 457:
result
END; # TOSTRING #
 
 
 
Line 276 ⟶ 462:
print( ( TOSTRING range expand( TORANGE "-6,-3--1,3-5,7-11,14,15,17-20" ), newline ) )
)
</syntaxhighlight>
</lang>
{{out}}
<pre>
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
</pre>
 
=={{header|APL}}==
{{works with|Dyalog APL}}
<syntaxhighlight lang="apl">range←{
aplnum←{⍎('¯',⎕D)[('-',⎕D)⍳⍵]}
∊{ 0::('Invalid range: ''',⍵,'''')⎕SIGNAL 11
n←aplnum¨(~<\(⊢≠∨\)⍵∊⎕D)⊆⍵
1=≢n:n
s e←n
(s+(⍳e-s-1))-1
}¨(⍵≠',')⊆⍵
}</syntaxhighlight>
 
{{out}}
 
<pre> range '-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
range '-6,--3--1,3-5,7-11,14,15,17-20'
Invalid range: '--3--1'
range'-6,--3--1,3-5,7-11,14,15,17-20'
range'-6,-3--1,3-5,11-7,14,15,17-20'
Invalid range: '11-7'
range'-6,-3--1,3-5,11-7,14,15,17-20'
∧</pre>
 
=={{header|AppleScript}}==
===Functional===
{{Trans|JavaScript}} (Functional ES5 version)
<syntaxhighlight lang="applescript">-- Each comma-delimited string is mapped to a list of integers,
-- and these integer lists are concatenated together into a single list
 
 
---------------------- RANGE EXPANSION ---------------------
 
-- expansion :: String -> [Int]
on expansion(strExpr)
-- The string (between commas) is split on hyphens,
-- and this segmentation is rewritten to ranges or minus signs
-- and evaluated to lists of integer values
-- signedRange :: String -> [Int]
script signedRange
-- After the first character, numbers preceded by an
-- empty string (resulting from splitting on hyphens)
-- and interpreted as negative
-- signedIntegerAppended:: [Int] -> String -> Int -> [Int] -> [Int]
on signedIntegerAppended(acc, strNum, iPosn, xs)
if strNum ≠ "" then
if iPosn > 1 then
set strSign to |λ|(0 < length of (item (iPosn - 1) of xs)) ¬
of bool("", "-")
else
set strSign to "+"
end if
acc & ((strSign & strNum) as integer)
else
acc
end if
end signedIntegerAppended
on |λ|(strHyphenated)
tupleRange(foldl(signedIntegerAppended, {}, ¬
splitOn("-", strHyphenated)))
end |λ|
end script
concatMap(signedRange, splitOn(",", strExpr))
end expansion
 
 
---------------------------- TEST --------------------------
on run
expansion("-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}
end run
 
 
--------------------- GENERIC FUNCTIONS --------------------
 
 
-- bool :: a -> a -> Bool -> a
on bool(tf, ff)
-- The evaluation of either tf or ff,
-- depending on a boolean value.
script
on |λ|(bln)
if bln then
set e to tf
else
set e to ff
end if
set c to class of e
if {script, handler} contains c then
|λ|() of mReturn(e)
else
e
end if
end |λ|
end script
end bool
 
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
script append
on |λ|(a, b)
a & b
end |λ|
end script
foldl(append, {}, map(f, xs))
end concatMap
 
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if n < m then
set d to -1
else
set d to 1
end if
set lst to {}
repeat with i from m to n by d
set end of lst to i
end repeat
return lst
end enumFromTo
 
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
 
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
 
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
 
-- splitOn :: Text -> Text -> [Text]
on splitOn(strDelim, strMain)
set {dlm, my text item delimiters} to {my text item delimiters, strDelim}
set xs to text items of strMain
set my text item delimiters to dlm
return xs
end splitOn
 
-- range :: (Int, Int) -> [Int]
on tupleRange(tuple)
if tuple = {} then
{}
else if length of tuple > 1 then
enumFromTo(item 1 of tuple, item 2 of tuple)
else
item 1 of tuple
end if
end tupleRange</syntaxhighlight>
{{Out}}
<syntaxhighlight lang="applescript">{-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20}</syntaxhighlight>
----
 
===Idiomatic===
 
<syntaxhighlight lang="applescript">on rangeExpansion(rangeExpression)
-- Split the expression at the commas, if any.
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to ","
set theRanges to rangeExpression's text items
set integerList to {}
set AppleScript's text item delimiters to "-"
repeat with thisRange in theRanges
-- Split each range or integer text at its dash(es), if any.
set rangeParts to thisRange's text items
-- A minus before the first integer will make leading text item "".
-- If this happens, insert the negative first value at the beginning of the parts list.
-- (AppleScript automatically coerces numeric text to number when the context demands.)
if (rangeParts begins with "") then set beginning of rangeParts to -(item 2 of rangeParts)
-- A minus before the second (or only) integer will make the penultimate text item "".
-- In this case, insert the negative last value at the end of the parts list.
if (((count rangeParts) > 1) and (item -2 of rangeParts is "")) then set end of rangeParts to -(end of rangeParts)
-- Append all the integers implied by the range to the integer list.
repeat with i from (beginning of rangeParts) to (end of rangeParts)
set end of integerList to i
end repeat
end repeat
set AppleScript's text item delimiters to astid
return integerList
end rangeExpansion
 
-- Demo code:
set rangeExpression to "-6,-3--1,3-5,7-11,14,15,17-20"
return rangeExpansion(rangeExpression)</syntaxhighlight>
 
{{output}}
<syntaxhighlight lang="applescript">{-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20}</syntaxhighlight>
 
=={{header|Arturo}}==
 
<syntaxhighlight lang="rebol">expandRange: function [rng][
flatten @ to :block
join.with:" " map split.by:"," rng 'x ->
replace replace replace x
{/^\-(\d+)/} "(neg $1)" {/\-\-(\d+)/}
"-(neg $1)" "-" ".."
]
 
print expandRange {-6,-3--1,3-5,7-11,14,15,17-20}</syntaxhighlight>
 
{{out}}
 
<pre>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</pre>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">msgbox % expand("-6,-3--1,3-5,7-11,14,15,17-20")
 
expand( range ) {
Line 291 ⟶ 718:
ret .= "," (A_Index-1) + f1
return SubStr(ret, 2)
}</langsyntaxhighlight>
 
=={{header|AWK}}==
 
<langsyntaxhighlight lang="awk">#!/usr/bin/awk -f
BEGIN { FS=","; }
 
Line 316 ⟶ 743:
}
return;
} </langsyntaxhighlight>
 
<pre>
Line 325 ⟶ 752:
 
=={{header|BBC BASIC}}==
<langsyntaxhighlight lang="bbcbasic"> PRINT FNrangeexpand("-6,-3--1,3-5,7-11,14,15,17-20")
END
Line 347 ⟶ 774:
ENDIF
UNTIL i% = 0
= r$</langsyntaxhighlight>
{{out}}
<pre>
Line 354 ⟶ 781:
 
=={{header|Bracmat}}==
<langsyntaxhighlight lang="bracmat"> ( expandRanges
= a b L
. @( !arg
Line 369 ⟶ 796:
)
& out$(str$(expandRanges$"-6,-3--1,3-5,7-11,14,15,17-20"))
</syntaxhighlight>
</lang>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
Line 375 ⟶ 802:
=={{header|C}}==
Recursive descent parser.
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
Line 452 ⟶ 879:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
Line 461 ⟶ 888:
=={{header|C sharp|C#}}==
{{works with|C sharp|3.0}}
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 490 ⟶ 917:
Console.WriteLine(string.Join(", ", values));
}
}</langsyntaxhighlight>
 
{{works with|C sharp|3.5+}}
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 523 ⟶ 950:
}
}
}</langsyntaxhighlight>
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <sstream>
#include <iterator>
Line 599 ⟶ 1,026:
else
std::cout << "an error occured.";
}</langsyntaxhighlight>
{{out}}
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
Line 605 ⟶ 1,032:
=={{header|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 <code>(split "-8--8") => (-8 -8)</code>.
<langsyntaxhighlight lang="clojure">(defn split [s sep]
(defn skipFirst [[x & xs :as s]]
(cond (empty? s) [nil nil]
Line 628 ⟶ 1,055:
 
> (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)</langsyntaxhighlight>
 
=={{header|COBOL}}==
{{works with|GNU Cobol|2.0}}
<langsyntaxhighlight lang="cobol"> >>SOURCE FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. expand-range.
Line 724 ⟶ 1,151:
END-IF
.
END PROGRAM display-edited-num.</langsyntaxhighlight>
 
Setup:
Line 738 ⟶ 1,165:
 
=={{header|Common Lisp}}==
<langsyntaxhighlight lang="lisp">(defun expand-ranges (string)
(loop
with prevnum = nil
Line 760 ⟶ 1,187:
 
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)</langsyntaxhighlight>
 
=={{header|Cowgol}}==
<syntaxhighlight lang="cowgol">include "cowgol.coh";
 
# Callback interface
interface RangeCb(n: int32);
 
# This will call `cb' for each number in the range, in ascending order.
# It will return NULL on success, or the location of an error if
# there is one.
sub Expand(ranges: [uint8], cb: RangeCb): (err: [uint8]) is
err := 0 as [uint8];
loop
# Grab first number
var n1: int32;
var next: [uint8];
(n1, next) := AToI(ranges);
if next == ranges then
# No number here!
err := ranges;
break;
elseif [next] == ',' or [next] == 0 then
# Only one number, not a range
cb(n1);
elseif [next] != '-' then
# No dash!
err := ranges;
break;
else
# Grab second number
ranges := @next next;
var n2: int32;
(n2, next) := AToI(ranges);
if next == ranges or n1 >= n2 then
# No second number, or first not before second
err := ranges;
break;
end if;
# We need all numbers from n1 to n2 inclusive
while n1 <= n2 loop
cb(n1);
n1 := n1 + 1;
end loop;
end if;
 
# stop if end reached
if [next] == 0 then break;
elseif [next] != ',' then
err := ranges;
break;
end if;
ranges := @next next;
end loop;
end sub;
 
# This function will use `Expand' above to expand a comma-separated
# range list, and reformat it as a comma-separated list of integers.
sub ExpandFmt(ranges: [uint8], buf: [uint8]): (err: [uint8]) is
# Format and add number to buffer
sub AddNum implements RangeCb is
buf := IToA(n, 10, buf);
[buf] := ',';
buf := @next buf;
end sub;
# Expand range, adding numbers to buffer
err := Expand(ranges, AddNum);
[@prev buf] := 0;
end sub;
 
# Expand and print, and/or give error
sub PrintExpansion(ranges: [uint8]) is
var buf: uint8[256];
var err := ExpandFmt(ranges, &buf[0]);
print(ranges);
print_nl();
print(" >> ");
if err == 0 as [uint8] then
# everything is OK
print(&buf[0]);
else
# error
print("error at: ");
print(err);
end if;
print_nl();
end sub;
 
# Try it on the given input
PrintExpansion("-6,-3--1,3-5,7-11,14,15,17-20");
 
# Try it on a couple of wrong ones
PrintExpansion("-6-3--1,3-5,7-11,14,15,17-20"); # misformatted range
PrintExpansion("-6,-3--1,5-3,7-11,14,15,17-20"); # numbers not in order</syntaxhighlight>
 
{{out}}
 
<pre>-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--1,3-5,7-11,14,15,17-20
>> error at: 3--1,3-5,7-11,14,15,17-20
-6,-3--1,5-3,7-11,14,15,17-20
>> error at: 3,7-11,14,15,17-20</pre>
 
=={{header|Crystal}}==
{{trans|Ruby}}
<syntaxhighlight lang="crystal">def range_expand(range)
range.split(',').flat_map do |part|
match = /^(-?\d+)-(-?\d+)$/.match(part)
if match
(match[1].to_i .. match[2].to_i).to_a
else
part.to_i
end
end
end
 
puts range_expand("-6,-3--1,3-5,7-11,14,15,17-20")</syntaxhighlight>
{{out}}
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.regex, std.conv, std.range, std.algorithm;
 
enum rangeEx = (string s) /*pure*/ => s.matchAll(`(-?\d+)-?(-?\d+)?,?`)
Line 770 ⟶ 1,319:
void main() {
"-6,-3--1,3-5,7-11,14,15,17-20".rangeEx.writeln;
}</langsyntaxhighlight>
{{out}}
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{Trans|Go}}
<syntaxhighlight lang="delphi">
program Range_expansion;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils;
 
const
input = '-6,-3--1,3-5,7-11,14,15,17-20';
 
var
r: TArray<Integer>;
last, i, n: Integer;
 
begin
for var part in input.Split([',']) do
begin
i := part.Substring(1).IndexOf('-');
if i = -1 then
begin
if not TryStrToInt(part, n) then
raise Exception.Create('Error: value invalid ' + part);
if Length(r) > 0 then
if last = n then
begin
raise Exception.Create('Error: Duplicate value:' + n.ToString);
end
else
begin
if last > n then
raise Exception.CreateFmt('Error: values not ordered: %s > %s', [last, n]);
end;
SetLength(r, Length(r) + 1);
r[High(r)] := n;
last := n;
end
else
begin
var n1 := 0;
var n2 := 0;
if not TryStrToInt(part.Substring(0, i + 1), n1) then
raise Exception.Create('Error: value invalid ' + part);
if not TryStrToInt(part.Substring(i + 2), n2) then
raise Exception.Create('Error: value invalid ' + part);
if n2 < n1 + 2 then
raise Exception.Create('Error: Invalid range' + part);
if Length(r) > 0 then
begin
if last = n1 then
raise Exception.Create('Error: Duplicate value: ' + n1.ToString);
if last > n1 then
raise Exception.CreateFmt('Error: Values not ordened: %d > %d', [last, n1]);
end;
 
for i := n1 to n2 do
begin
SetLength(r, Length(r) + 1);
r[High(r)] := i;
end;
 
last := n2;
end;
end;
write('expanded: ');
for var rr in r do
begin
write(rr, ',');
end;
readln;
end.</syntaxhighlight>
 
 
=={{header|DWScript}}==
<syntaxhighlight lang="pascal">
function ExpandRanges(ranges : String) : array of Integer;
begin
for var range in ranges.Split(',') do begin
var separator = range.IndexOf('-', 2);
if separator > 0 then begin
for var i := range.Left(separator-1).ToInteger to range.Copy(separator+1).ToInteger do
Result.Add(i);
end else begin
Result.Add(range.ToInteger)
end;
end;
end;
 
var expanded := ExpandRanges('-6,-3--1,3-5,7-11,14,15,17-20');
PrintLn(JSON.Stringify(expanded));
</syntaxhighlight>
{{out}}
<pre>[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]</pre>
 
=={{header|Dyalect}}==
 
{{trans|Go}}
 
<syntaxhighlight lang="dyalect">func main() {
let input = "-6,-3--1,3-5,7-11,14,15,17-20"
print("range: \(input)")
var r = []
var last = 0
for part in input.Split(',') {
var i = part[1..].IndexOf('-')
if i == -1 {
var n = Integer(part)
if r.Length() > 0 {
return print("duplicate value: \(n)") when last == n
return print("values not ordered: \(last) > \(n)") when last > n
}
r.Add(n)
last = n
} else {
var n1 = Integer(part[..i])
var n2 = Integer(part[(i + 2)..])
return print("invalid range: \(part)") when n2 < n1 + 2
if r.Length() > 0 {
return print("duplicate value: \(n1)") when last == n1
return print("values not ordered: \(last) > \(n1)") when last > n1
}
for i in n1..n2 {
r.Add(i)
}
last = n2
}
}
print("expanded: \(r)")
}
main()</syntaxhighlight>
 
{{out}}
 
<pre>range: -6,-3--1,3-5,7-11,14,15,17-20
expanded: [-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
 
=={{header|EchoLisp}}==
<langsyntaxhighlight lang="scheme">
;; parsing [spaces][-]digit(s)-[-]digit(s)[spaces]
(define R (make-regexp "^ *(\-?\\d+)\-(\-?\\d+) *$" ))
Line 801 ⟶ 1,492:
(ranges task)
→ (-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20)
</syntaxhighlight>
</lang>
 
=={{header|Elixir}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="elixir">defmodule RC do
def expansion(range) do
Enum.flat_map(String.split(range, ","), fn part ->
Line 816 ⟶ 1,507:
end
 
IO.inspect RC.expansion("-6,-3--1,3-5,7-11,14,15,17-20")</langsyntaxhighlight>
 
{{out}}
Line 824 ⟶ 1,515:
 
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( range ).
 
Line 839 ⟶ 1,530:
expansion_individual( {ok, [N], []} ) -> N;
expansion_individual( {ok, [Start], "-" ++ Stop_string} ) -> lists:seq( Start, erlang:list_to_integer(Stop_string) ).
</syntaxhighlight>
</lang>
 
{{out}}
Line 845 ⟶ 1,536:
34> range:task().
[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]
</pre>
 
=={{header|F_Sharp|F#}}==
<syntaxhighlight 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")</syntaxhighlight>
{{out}}
<pre>[-6; -3; -2; -1; 3; 4; 5; 7; 8; 9; 10; 11; 14; 15; 17; 18; 19; 20]</pre>
 
=={{header|Factor}}==
<code>R/ (?<=\d)-/ re-split</code> says: ''split only on hyphens immediately preceded by a digit.''
<syntaxhighlight lang="factor">USING: kernel math.parser math.ranges prettyprint regexp
sequences sequences.extras splitting ;
 
: expand ( str -- seq )
"," split [
R/ (?<=\d)-/ re-split [ string>number ] map
dup length 2 = [ first2 [a,b] ] when
] map-concat ;
 
"-6,-3--1,3-5,7-11,14,15,17-20" expand .</syntaxhighlight>
{{out}}
<pre>
{ -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 }
</pre>
 
=={{header|Forth}}==
<langsyntaxhighlight lang="forth">: >snumber ( str len -- 'str 'len n )
0. 2swap
over c@ [char] - = if
Line 872 ⟶ 1,607:
repeat 2drop ;
 
s" -6,-3--1,3-5,7-11,14,15,17-20" expand</langsyntaxhighlight>
 
=={{header|F_Sharp|F#Fortran}}==
In order to save on the annoyance of having to declare the type of function ERANGE in each routine that invokes it (just one, here), the F90 MODULE protocol is convenient. F90 also allows for routines to contain service routines that share the context without massive parameter lists or shared COMMON areas, though alternatively, the shared variables could be inside the MODULE which would contain the service routines as separate routines also inside the module. But for this, one should not share variables having short names such as <code>I</code>. Otherwise, this would be F77 style except for the usage of the <code>I0</code> format code in subroutine SPLOT. If that were unavailable, code <code>I12</code> could be used and leading spaces would have to be skipped instead. The DO WHILE loop with its EXIT and labels would have to be less decorative for F77.
<lang fsharp>open System.Text.RegularExpressions
 
The standard problem of "How long is a piece of string?" applies yet again. Arrays and character variables have to be declared with some fixed size, and the usual approach is "surely big enough". The test input is not a problem, because the caller can use the needed size and pass that to ERANGE as a parameter, whatever its size. But function ERANGE's result must have some pre-declared size, and for this example, CHARACTER*200 will do. Via a great deal of blather, varying-size character variables can be defined and used in F90/95, and F2003 has standardised a method of doing this, whereby whenever something like <code>ALINE = ALINE // "stuff"</code> is executed, variable ALINE is reallocated with additional space. This involves copying the old content to the newly allocated larger storage area, so doing a lot of this would be bad snowballing.
// 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
 
The method is to grind through the input string expecting to find a ''number'' or a ''number - number'' pair (signed numbers allowed), followed by a comma if more is to follow. The state of the scan is represented by position within the scanning code rather than mess with state variables, so it is convenient to have service routines for the resulting repetition of basic actions. No checks are made for improper input, for instance a string ending with a comma. Those of a delicate disposition may be troubled by functions that don't just return a result but also mess with their parameter and change their environment. Here, the results from the functions assist with the flow of control through the scan, it is the side effects that manipulate the data.
// 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
 
A frustrating problem with many modern computer languages is the absence of a "shortcut" evaluation praxis for logical expressions; in Fortran's case the modern standard is that there is no standard. So a test <code>I<=LEN(TEXT) & TEXT(I:I)''etc.''</code> can't be relied upon to dodge out-of-bounds errors, and a flabby two-statement sequence is required instead. Similarly, few Fortran compilers allow for a function being evaluated via a WRITE statement to itself succeed in using a WRITE statement internally, though some do if one usage is free-format and the other formatted. If necessary, subroutine SPLOT could be re-written to convert an integer to a digit string without a WRITE statement, even for negative integers. And some compilers have difficulty with the use of the function name as a variable within the function so that it is safest to develop the result in an ordinary variable and then remember to assign its value to the function name just before exit.
let expand (desc:string) =
 
desc.Split(',')
A single number is made internally into a two-number range sequence, which values are used as the bounds for a DO-loop to generate the numbers for output. Despite the '''The range syntax is to be used only for, and for every range that expands to more than two values''', I see no reason for this restriction (say because otherwise some fancy method would be stymied, except I can think of no such fancier method) and I have no desire to interpose some sort of error message, a tedious business that requires a wider interface between a routine and its caller. Similarly, if a range of 40-30 were to appear, why not take it at face value? <syntaxhighlight lang="fortran"> MODULE HOMEONTHERANGE
|> List.ofArray
CONTAINS !The key function.
|> List.collect parseRange
CHARACTER*200 FUNCTION ERANGE(TEXT) !Expands integer ranges in a list.
Can't return a character value of variable size.
CHARACTER*(*) TEXT !The list on input.
CHARACTER*200 ALINE !Scratchpad for output.
INTEGER N,N1,N2 !Numbers in a range.
INTEGER I,I1 !Steppers.
ALINE = "" !Scrub the scratchpad.
L = 0 !No text has been placed.
I = 1 !Start at the start.
CALL FORASIGN !Find something to look at.
Chug through another number or number - number range.
R:DO WHILE(EATINT(N1)) !If I can grab a first number, a term has begun.
N2 = N1 !Make the far end the same.
IF (PASSBY("-")) CALL EATINT(N2) !A hyphen here is not a minus sign.
IF (L.GT.0) CALL EMIT(",") !Another, after what went before?
DO N = N1,N2,SIGN(+1,N2 - N1) !Step through the range, possibly backwards.
CALL SPLOT(N) !Roll a number.
IF (N.NE.N2) CALL EMIT(",") !Perhaps another follows.
END DO !On to the next number.
IF (.NOT.PASSBY(",")) EXIT R !More to come?
END DO R !So much for a range.
Completed the scan. Just return the result.
ERANGE = ALINE(1:L) !Present the result. Fiddling ERANGE is bungled by some compilers.
CONTAINS !Some assistants for the scan to save on repetition and show intent.
SUBROUTINE FORASIGN !Look for one.
1 IF (I.LE.LEN(TEXT)) THEN !After a thingy,
IF (TEXT(I:I).LE." ") THEN !There may follow spaces.
I = I + 1 !So,
GO TO 1 !Speed past any.
END IF !So that the caller can see
END IF !Whatever substantive character follows.
END SUBROUTINE FORASIGN !Simple enough.
 
LOGICAL FUNCTION PASSBY(C) !Advances the scan if a certain character is seen.
Could consider or ignore case for letters, but this is really for single symbols.
CHARACTER*1 C !The character.
PASSBY = .FALSE. !Pessimism.
IF (I.LE.LEN(TEXT)) THEN !Can't rely on I.LE.LEN(TEXT) .AND. TEXT(I:I)...
IF (TEXT(I:I).EQ.C) THEN !Curse possible full evaluation.
PASSBY = .TRUE. !Righto, C is seen.
I = I + 1 !So advance the scan.
CALL FORASIGN !And see what follows.
END IF !So much for a match.
END IF !If there is something to be uinspected.
END FUNCTION PASSBY !Can't rely on testing PASSBY within PASSBY either.
 
LOGICAL FUNCTION EATINT(N) !Convert text into an integer.
INTEGER N !The value to be ascertained.
INTEGER D !A digit.
LOGICAL NEG !In case of a minus sign.
EATINT = .FALSE. !Pessimism.
IF (I.GT.LEN(TEXT)) RETURN !Anything to look at?
N = 0 !Scrub to start with.
IF (PASSBY("+")) THEN !A plus sign here can be ignored.
NEG = .FALSE. !So, there's no minus sign.
ELSE !And if there wasn't a plus,
NEG = PASSBY("-") !A hyphen here is a minus sign.
END IF !One way or another, NEG is initialised.
IF (I.GT.LEN(TEXT)) RETURN !Nothing further! We wuz misled!
Chug through digits. Can develop -2147483648, thanks to the workings of two's complement.
10 D = ICHAR(TEXT(I:I)) - ICHAR("0") !Hope for a digit.
IF (0.LE.D .AND. D.LE.9) THEN !Is it one?
N = N*10 + D !Yes! Assimilate it, negatively.
I = I + 1 !Advance one.
IF (I.LE.LEN(TEXT)) GO TO 10 !And see what comes next.
END IF !So much for a sequence of digits.
IF (NEG) N = -N !Apply the minus sign.
EATINT = .TRUE. !Should really check for at least one digit.
CALL FORASIGN !Ram into whatever follows.
END FUNCTION EATINT !Integers are easy. Could check for no digits seen.
 
SUBROUTINE EMIT(C) !Rolls forth one character.
CHARACTER*1 C !The character.
L = L + 1 !Advance the finger.
IF (L.GT.LEN(ALINE)) STOP "Ran out of ALINE!" !Maybe not.
ALINE(L:L) = C !And place the character.
END SUBROUTINE EMIT !That was simple.
 
SUBROUTINE SPLOT(N) !Rolls forth a signed number.
INTEGER N !The number.
CHARACTER*12 FIELD !Sufficient for 32-bit integers.
INTEGER I !A stepper.
WRITE (FIELD,"(I0)") N !Roll the number, with trailing spaces.
DO I = 1,12 !Now transfer the ALINE of the number.
IF (FIELD(I:I).LE." ") EXIT !Up to the first space.
CALL EMIT(FIELD(I:I)) !One by one.
END DO !On to the end.
END SUBROUTINE SPLOT !Not so difficult either.
END FUNCTION ERANGE !A bit tricky.
END MODULE HOMEONTHERANGE
 
PROGRAM POKE
USE HOMEONTHERANGE
CHARACTER*(200) SOME
SOME = "-6,-3--1,3-5,7-11,14,15,17-20"
SOME = ERANGE(SOME)
WRITE (6,*) SOME !If ERANGE(SOME) then the function usually can't write output also.
END</syntaxhighlight>
 
Output: <pre> -6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
 
A check by using -2147483648 showed that EATINT develops the correct value even if N is built positively. Adding 8 to 2147483640 VIA <code>N = N*10 + D</code> indeed produces -2147483648 (and NEG was '''t'''), but the <code>IF (NEG) N = -N</code> still results in -2147483648 because of the working of (flip all bits and add one): invert(-2147483648) = 2147483647, and, adding one to that produces -2147483648.
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64
 
Sub split (s As Const String, sepList As Const String, result() As String)
If s = "" OrElse sepList = "" Then
Redim result(0)
result(0) = s
Return
End If
Dim As Integer i, j, count = 0, empty = 0, length
Dim As Integer position(Len(s) + 1)
position(0) = 0
For i = 0 To len(s) - 1
For j = 0 to Len(sepList) - 1
If s[i] = sepList[j] Then
count += 1
position(count) = i + 1
End If
Next j
Next i
Redim result(count)
If count = 0 Then
result(0) = s
Return
End If
position(count + 1) = len(s) + 1
For i = 1 To count + 1
length = position(i) - position(i - 1) - 1
result(i - 1) = Mid(s, position(i - 1) + 1, length)
Next
End Sub
 
Function expandRange(s As Const String) As String
If s = "" Then Return ""
Dim b() As String
Dim c() As String
Dim result As String = ""
Dim As Integer start = 0, finish = 0, length
split s, ",", b()
For i As Integer = LBound(b) To UBound(b)
split b(i), "-", c()
length = UBound(c) - LBound(c) + 1
If length = 1 Then
start = ValLng(c(LBound(c)))
finish = start
ElseIf length = 2 Then
If Left(b(i), 1) = "-" Then
start = -ValLng(c(UBound(c)))
finish = start
Else
start = ValLng(c(LBound(c)))
finish = ValLng(c(UBound(c)))
End If
ElseIf length = 3 Then
start = -ValLng(c(LBound(c) + 1))
finish = ValLng(c(UBound(c)))
Else
start = -ValLng(c(LBound(c) + 1))
finish = -ValLng(c(UBound(c)))
End If
For j As Integer = start To finish
result += Str(j) + ", "
Next j
Next i
Return Left(result, Len(result) - 2) '' get rid of final ", "
End Function
 
Dim s As String = "-6,-3--1,3-5,7-11,14,15,17-20"
Print expandRange(s)
Print
Print "Press any key to quit"
Sleep</syntaxhighlight>
 
printfn "%A" (expand "-6,-3--1,3-5,7-11,14,15,17-20")</lang>
{{out}}
<pre>
<pre>[-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|Go}}==
A version rather strict with input
<langsyntaxhighlight lang="go">package main
 
import (
Line 966 ⟶ 1,870:
}
fmt.Println("expanded:", r)
}</langsyntaxhighlight>
 
=={{header|Groovy}}==
Line 976 ⟶ 1,880:
# express as a string
# unwrap the list delimiters
<langsyntaxhighlight lang="groovy">def expandRanges = { compressed ->
Eval.me('['+compressed.replaceAll(~/(\d)-/, '$1..')+']').flatten().toString()[1..-2]
}</langsyntaxhighlight>
Test:
<langsyntaxhighlight lang="groovy">def s = '-6,-3--1,3-5,7-11,14,15,17-20'
println (expandRanges(s))</langsyntaxhighlight>
{{out}}
<pre>-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20</pre>
Line 987 ⟶ 1,891:
=={{header|Haskell}}==
Given either of the below implementations of <code>expandRange</code>:
<langsyntaxhighlight 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]</langsyntaxhighlight>
===With conventional list processing===
<langsyntaxhighlight lang="haskell">expandRange :: String -> [Int]
expandRange = concatMap f . split ','
where f str@(c : cs) | '-' `elem` cs = [read (c : a) .. read b]
Line 999 ⟶ 1,903:
split delim [] = []
split delim l = a : split delim (dropWhile (== delim) b)
where (a, b) = break (== delim) l</langsyntaxhighlight>
===With a parser===
<syntaxhighlight lang="haskell">{-# LANGUAGE FlexibleContexts #-}
<lang haskell>import Control.Applicative (Applicative((<*>),(*>)),(<$>))
 
import Text.Parsec
 
expandRange :: String -> Maybe [Int]
expandRange =
expandRange = either (const Nothing) Just . parse rangeParser ""
either
(const Nothing)
Just
. parse rangeParser ""
 
rangeParser :: Parser [Int]
(Enum a, Read a, Stream s m Char) =>
ParsecT s u m [a]
rangeParser = concat <$> (item `sepBy` char ',')
where item = do n1 <- num
item = do
n2 <- option n1 (char '-' *> num)
return [n1 ..<- n2]num
n2 <- numoption ::n1 Parser(char Int'-' *> num)
return [n1 .. n2]
num = read `dot` (++) <$> option "" (string "-") <*> many1 digit
num =
dot = ((.).(.))</lang>
read `dot` (<>) <$> option "" (string "-")
<*> many1 digit
dot = (.) . (.)
 
main :: IO ()
main = print $ expandRange "-6,-3--1,3-5,7-11,14,15,17-20"</syntaxhighlight>
{{Out}}
<pre>Just [-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]</pre>
 
=={{header|Icon}} and {{header|Unicon}}==
<langsyntaxhighlight Iconlang="icon">procedure main()
s := "-6,-3--1,3-5,7-11,14,15,17-20"
write("Input string := ",s)
Line 1,041 ⟶ 1,960:
every (s := "[ ") ||:= !L || " "
return s || "]"
end</langsyntaxhighlight>
{{out}}
<pre>Input string := -6,-3--1,3-5,7-11,14,15,17-20
Line 1,047 ⟶ 1,966:
 
=={{header|J}}==
<langsyntaxhighlight lang="j">require'strings'
thru=: <./ + i.@(+*)@-~
num=: _&".
normaliz=: rplc&(',-';',_';'--';'-_')@,~&','
subranges=:<@(thru/)@(num;._2)@,&'-';._1
rngexp=: ;@subranges@normaliz</langsyntaxhighlight>
{{out|Example}}
<langsyntaxhighlight 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</langsyntaxhighlight>
 
Notes:
Line 1,067 ⟶ 1,986:
subranges: given the result of normaliz, return a sequence of boxes (one box for each comma). Each box contains the subrange which is described after its comma.
 
As an aside, note also that thru/ is an identity function when applied to a single number. This is because (verb/) inserts the verb between each number (or each item in a list), and this is an identity function on a single number, regardless of any definition of the verb. Fortunately, this is consistent with the definition of thru (and is also consistent for any combining verb which has an identity element). Note that this is very similar to the self-justifying [[wp:Fold_(higher-order_function)|fold]] definition (specifically a right fold, because of J's structure), but fold can be considerably harder to reason about because it explicitly avoids the concept of identity for combining functions. You should maybe consider using a loop in contexts where this is an issue.
 
Also note that current versions of J no longer need <code>require'strings'</code> as those routines are included by default. (But let's leave this in place because current versions of J still have some catching up to do in some areas, such as lab support.)
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.util.*;
 
class RangeExpander implements Iterator<Integer>, Iterable<Integer> {
Line 1,082 ⟶ 2,003:
private int nextRangeValue;
 
public RangeExpander(String stringrange) {
String[] tokens = stringrange.split("\\s*,\\s*");
this.tokensIterator = Arrays.asList(tokens).iterator();
}
Line 1,134 ⟶ 2,055:
}
}
}</langsyntaxhighlight>
 
=={{header|JavaScript}}==
 
===Imperative (Spidermonkey version )===
 
<langsyntaxhighlight lang="javascript">#!/usr/bin/env js
 
function main() {
Line 1,174 ⟶ 2,095:
 
main();
</syntaxhighlight>
</lang>
 
{{out}}
-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
 
===Functional===
 
====ES5====
 
<syntaxhighlight lang="javascript">(function (strTest) {
'use strict';
 
// s -> [n]
function expansion(strExpr) {
 
// concat map yields flattened output list
return [].concat.apply([], strExpr.split(',')
.map(function (x) {
return x.split('-')
.reduce(function (a, s, i, l) {
 
// negative (after item 0) if preceded by an empty string
// (i.e. a hyphen-split artefact, otherwise ignored)
return s.length ? i ? a.concat(
parseInt(l[i - 1].length ? s :
'-' + s, 10)
) : [+s] : a;
}, []);
 
// two-number lists are interpreted as ranges
})
.map(function (r) {
return r.length > 1 ? range.apply(null, r) : r;
}));
}
 
 
// [m..n]
function range(m, n) {
return Array.apply(null, Array(n - m + 1))
.map(function (x, i) {
return m + i;
});
}
 
return expansion(strTest);
 
})('-6,-3--1,3-5,7-11,14,15,17-20');</syntaxhighlight>
 
{{Out}}
 
<syntaxhighlight lang="javascript">[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</syntaxhighlight>
 
 
====ES6====
<syntaxhighlight lang="javascript">(() => {
"use strict";
 
// ----------------- RANGE EXPANSION -----------------
 
// rangeExpansion :: String -> [Int]
const rangeExpansion = rangeString =>
// A list of integers parsed from a
// comma-delimited string which may include
// (rising) hyphenated ranges.
rangeString.split(",")
.flatMap(x => {
const ns = x.split("-")
.reduce((a, s, i, xs) =>
Boolean(s) ? (
0 < i ? a.concat(
parseInt(
xs[i - 1].length ? (
s
) : `-${s}`,
10
)
) : [Number(s)]
) : a,
[]
);
 
return 2 === ns.length ? (
uncurry(enumFromTo)(ns)
) : ns;
});
 
 
// ---------------------- TEST -----------------------
// main :: IO ()
const main = () =>
rangeExpansion("-6,-3--1,3-5,7-11,14,15,17-20");
 
 
// --------------------- GENERIC ---------------------
 
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = m =>
n => Array.from({
length: 1 + n - m
}, (_, i) => m + i);
 
 
// uncurry :: (a -> b -> c) -> ((a, b) -> c)
const uncurry = f =>
// A function over a pair, derived
// from a curried function.
(...args) => {
const [x, y] = Boolean(args.length % 2) ? (
args[0]
) : args;
 
return f(x)(y);
};
 
 
// MAIN ---
return JSON.stringify(main());
})();</syntaxhighlight>
{{Out}}
<pre>[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]</pre>
 
=={{header|jq}}==
{{works with|jq|with regex support}}
<langsyntaxhighlight lang="jq">def expand_range:
def number: "-?[0-9]+";
def expand: [range(.[0]; .[1] + 1)];
Line 1,191 ⟶ 2,229:
else sub( "(?<x>\(number))-(?<y>\(number))"; "\(.x):\(.y)")
| split(":") | map(tonumber) | expand
end));</langsyntaxhighlight>
'''Example''':
<langsyntaxhighlight lang="jq">"-6,-3--1,3-5,7-11,14,15,17-20" | expand_range</langsyntaxhighlight>
{{out}}$ jq -c -n -f Range_expansion.jq
[-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20]
 
=={{header|Jsish}}==
{{trans|Javascript}}
<syntaxhighlight lang="javascript">#!/usr/bin/env jsish
"use strict";
 
/* Range expansion, in Jsish */
function rangeExpand(rangeExpr) {
function getFactors(term) {
var matches = term.match(/(-?[0-9]+)-(-?[0-9]+)/);
if (!matches) return {first:Number(term)};
return {first:Number(matches[1]), last:Number(matches[2])};
}
function expandTerm(term) {
var factors = getFactors(term);
if (factors.length < 2) return [factors.first];
var range = [];
for (var n = factors.first; n <= factors.last; n++) {
range.push(n);
}
return range;
}
 
var result = [];
var terms = rangeExpr.split(",");
for (var t in terms) {
result = result.concat(expandTerm(terms[t]));
}
 
return result;
}
 
if (Interp.conf('unitTest')) {
; rangeExpand('-6,-3--1,3-5,7-11,14,15,17-20');
}
 
/*
=!EXPECTSTART!=
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 ]
=!EXPECTEND!=
*/</syntaxhighlight>
 
{{out}}
<pre>prompt$ jsish --U rangeExpansion.jsi
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>
 
=={{header|Julia}}==
<langsyntaxhighlight Julialang="julia">slurp(s) = readcsv(IOBuffer(s))
 
conv(s)= colon(map(x->parse(Int,x),match(r"^(-?\d+)-(-?\d+)$", s).captures)...)
 
expand(s) = mapreduce(x -> isa(x,Number)? Int(x) : conv(x), vcat, slurp(s))</langsyntaxhighlight>
{{out}}
<pre>julia> show(expand("-6,-3--1,3-5,7-11,14,15,17-20"))
Line 1,208 ⟶ 2,293:
 
=={{header|K}}==
<langsyntaxhighlight 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}</langsyntaxhighlight>
{{out|Example}}
<langsyntaxhighlight 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</langsyntaxhighlight>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.0.6
 
fun expandRange(s: String): MutableList<Int> {
val list = mutableListOf<Int>()
val items = s.split(',')
var first: Int
var last: Int
for (item in items) {
val count = item.count { it == '-' }
if (count == 0 || (count == 1 && item[0] == '-'))
list.add(item.toInt())
else {
val items2 = item.split('-')
if (count == 1) {
first = items2[0].toInt()
last = items2[1].toInt()
}
else if (count == 2) {
first = items2[1].toInt() * -1
last = items2[2].toInt()
}
else {
first = items2[1].toInt() * -1
last = items2[3].toInt() * -1
}
for (i in first..last) list.add(i)
}
}
return list
}
 
fun main(args: Array<String>) {
val s = "-6,-3--1,3-5,7-11,14,15,17-20"
println(expandRange(s))
}</syntaxhighlight>
 
{{out}}
<pre>
[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]
</pre>
 
=={{header|Lasso}}==
<langsyntaxhighlight lang="lasso">define range_expand(expression::string) => {
local(parts) = regexp(`^(-?\d+)-(-?\d+)$`)
Line 1,231 ⟶ 2,357:
}
 
range_expand(`-6,-3--1,3-5,7-11,14,15,17-20`)</langsyntaxhighlight>
 
{{out}}
<pre>-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20</pre>
 
 
=={{header|Liberty BASIC}}==
<langsyntaxhighlight lang="lb">print ExpandRange$( "-6,-3--1,3-5,7-11,14,15,17-20")
end
 
Line 1,260 ⟶ 2,385:
ItemCount = ItemCount + 1
wend
end function</langsyntaxhighlight>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
 
=={{header|Lingo}}==
<syntaxhighlight lang="lingo">-- Note: currently does not support extra white space in input string
on expandRange (str)
res = ""
_player.itemDelimiter = ","
cnt = str.item.count
repeat with i = 1 to cnt
part = str.item[i]
pos = offset("-", part.char[2..part.length])
if pos>0 then
a = integer(part.char[1..pos])
b = integer(part.char[pos+2..part.length])
repeat with j = a to b
put j&"," after res
end repeat
else
put part&"," after res
end if
end repeat
delete the last char of res
return res
end</syntaxhighlight>
<syntaxhighlight lang="lingo">put 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"</syntaxhighlight>
 
=={{header|LiveCode}}==
<langsyntaxhighlight LiveCodelang="livecode">function range beginning ending stepping
local tRange, tBegin, tEnd, tstep
if stepping is empty or stepping is 0 then
Line 1,302 ⟶ 2,452:
end repeat
return z
end expandRange</langsyntaxhighlight>
 
Test
<langsyntaxhighlight LiveCodelang="livecode">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 </langsyntaxhighlight>
 
=={{header|Lua}}==
 
<langsyntaxhighlight lang="lua">function range(i, j)
local t = {}
for n = i, j, i<j and 1 or -1 do
Line 1,337 ⟶ 2,487:
 
local ranges = "-6,-3--1,3-5,7-11,14,15,17-20"
print(table.concat(expand_ranges(ranges), ', '))</langsyntaxhighlight>
 
Due to the way Lua's <code>tonumber</code> function works and the way the string pattern to parse ranges is written, whitespace is allowed around commas and the dash separating the range start and end (but not between the plus/minus sign and the number).
Line 1,347 ⟶ 2,497:
 
=={{header|Maple}}==
<syntaxhighlight lang="maple">
<lang Maple>
ExpandRanges := proc( s :: string )
uses StringTools;
Line 1,385 ⟶ 2,535:
map( DoOne, map( Trim, Split( s, "," ) ) )
end proc:
</syntaxhighlight>
</lang>
Running this on the example input we get the following.
<syntaxhighlight lang="maple">
<lang Maple>
> rng := "-6,-3--1,3-5,7-11,14,15,17-20":
> ExpandRanges( rng );
[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]
</syntaxhighlight>
</lang>
Here is an additional example which my first attempt got wrong.
<syntaxhighlight lang="maple">
<lang Maple>
> rng := "-6,-3-1,3-5,7-11,14,15,17-20":
> ExpandRanges( rng );
[-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="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<>"]"] ]</langsyntaxhighlight>
{{out|Example}}
<pre>rangeexpand["-6,-3--1,3-5,7-11,14,15,17-20"]
Line 1,408 ⟶ 2,558:
 
=={{header|MATLAB}} / {{header|Octave}}==
<langsyntaxhighlight MATLABlang="matlab">function L=range_expansion(S)
% Range expansion
if nargin < 1;
Line 1,420 ⟶ 2,570:
S(ixr)=':';
S=['[',S,']'];
L=eval(S);</langsyntaxhighlight>
Usage:
<pre>
Line 1,428 ⟶ 2,578:
 
</pre>
 
=={{header|MiniScript}}==
<syntaxhighlight lang="miniscript">pullInt = function(chars)
numstr = chars.pull
while chars and chars[0] != "," and chars[0] != "-"
numstr = numstr + chars.pull
end while
return val(numstr)
end function
expandRange = function(s)
result = []
chars = s.split("")
while chars
num = pullInt(chars)
if not chars or chars.pull == "," then
result.push num
else
result = result + range(num, pullInt(chars))
chars.pull // skip "," after range
end if
end while
return result
end function
 
print expandRange("-6,-3--1,3-5,7-11,14,15,17-20")</syntaxhighlight>
{{out}}
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
 
=={{header|MUMPS}}==
<langsyntaxhighlight MUMPSlang="mumps">RANGEXP(X) ;Integer range expansion
NEW Y,I,J,X1,H SET Y=""
FOR I=1:1:$LENGTH(X,",") DO
Line 1,439 ⟶ 2,617:
.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</langsyntaxhighlight>
{{out|Example}}
<pre>USER>SET U="-6,-3--1,3-5,7-11,14,15,17-20"
Line 1,448 ⟶ 2,626:
=={{header|NetRexx}}==
Translation of: [[Range_expansion#Version_2_somewhat_simplified_.21.3F.21|Rexx Version 2]]
<langsyntaxhighlight NetRexxlang="netrexx">/*NetRexx program to expand a range of integers into a list. *************
* 09.08.2012 Walter Pachl derived from my Rexx version
* Changes: translate(old,' ',',') -> old.translate(' ',',')
Line 1,482 ⟶ 2,660:
End
Say 'new='new /*show the expanded list */
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,490 ⟶ 2,668:
 
=={{header|Nim}}==
<syntaxhighlight lang ="nim">import parseutils, re, strutils
 
proc expandRange(input: string): string =
var output: seq[string] = @[]
for range in input.split(','):
var sep = range.find('-', 1)
Line 1,513 ⟶ 2,691:
return output.join(",")
 
echo("-6,-3--1,3-5,7-11,14,15,17-20".expandRange)</langsyntaxhighlight>
 
{{out}}
Line 1,520 ⟶ 2,698:
=={{header|Oberon-2}}==
Oxford Oberon-2
<langsyntaxhighlight lang="oberon2">
MODULE LIVector;
IMPORT SYSTEM;
Line 1,757 ⟶ 2,935:
END ExpandRange.
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,764 ⟶ 2,942:
 
=={{header|OCaml}}==
<langsyntaxhighlight 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
Line 1,786 ⟶ 2,964:
let exp = range_expand rng in
List.iter (Printf.printf " %d") exp;
print_newline ()</langsyntaxhighlight>
 
=={{header|Oforth}}==
<syntaxhighlight lang="oforth">: addRange( s res -- )
| i n |
s asInteger dup ifNotNull: [ res add return ] drop
s indexOfFrom('-', 2) ->i
s left( i 1- ) asInteger s right( s size i - ) asInteger
for: n [ n res add ]
;
 
: rangeExpand ( s -- [ n ] )
ArrayBuffer new s wordsWith( ',' ) apply( #[ over addRange ] ) ;</syntaxhighlight>
 
=={{header|ooRexx}}==
<syntaxhighlight lang="oorexx">
<lang ooRexx>
list = '-6,-3--1,3-5,7-11,14,15,17-20'
expanded = expandRanges(list)
Line 1,820 ⟶ 3,010:
end
return expanded
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,828 ⟶ 3,018:
 
=={{header|Oz}}==
<langsyntaxhighlight lang="oz">declare
fun {Expand RangeDesc}
{Flatten
Line 1,857 ⟶ 3,047:
in
{System.showInfo
{Value.toVirtualString {Expand "-6,-3--1,3-5,7-11,14,15,17-20"} 100 100}}</langsyntaxhighlight>
{{out|Sample output}}
<langsyntaxhighlight lang="oz">[~6 ~3 ~2 ~1 3 4 5 7 8 9 10 11 14 15 17 18 19 20]</langsyntaxhighlight>
 
=={{header|Perl}}==
One-liner:
<langsyntaxhighlight Perllang="perl">sub rangex {
map { /^(.*\d)-(.+)$/ ? $1..$2 : $_ } split /,/, shift
}
 
# Test and display
print join(',', rangex('-6,-3--1,3-5,7-11,14,15,17-20')), "\n";</langsyntaxhighlight>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
 
Alternative:
<langsyntaxhighlight Perllang="perl">sub rangex {
(my $range = shift) =~ s/(?<=\d)-/../g;
eval $range;
}</langsyntaxhighlight>
 
=={{header|Perl 6Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Perl6>sub range-expansion (Str $range-description) {
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
my $range-pattern = rx/ ( '-'? \d+ ) '-' ( '-'? \d+) /;
<span style="color: #008080;">function</span> <span style="color: #000000;">range_expansion</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">range</span><span style="color: #0000FF;">)</span>
my &expand = -> $term { $term ~~ $range-pattern ?? +$0..+$1 !! $term };
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range</span><span style="color: #0000FF;">,</span><span style="color: #008000;">','</span><span style="color: #0000FF;">),</span>
return $range-description.split(',').map(&expand)
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
}
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
 
<span style="color: #004080;">string</span> <span style="color: #000000;">si</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
say range-expansion('-6,-3--1,3-5,7-11,14,15,17-20').join(', ');</lang>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">si</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">to_number</span><span style="color: #0000FF;">(</span><span style="color: #000000;">si</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">else</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">startrange</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_number</span><span style="color: #0000FF;">(</span><span style="color: #000000;">si</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]),</span>
<span style="color: #000000;">endofrange</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_number</span><span style="color: #0000FF;">(</span><span style="color: #000000;">si</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">=</span><span style="color: #000000;">startrange</span> <span style="color: #008080;">to</span> <span style="color: #000000;">endofrange</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">range_expansion</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"-6,-3-1,3-5,7-11,14,15,17-20"</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">range_expansion</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"-6,-3--1,3-5,7-11,14,15,17-20"</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
<pre>-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20</pre>
{-6,-3,-2,-1,0,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>
 
=={{header|Phixmonti}}==
Require Phixmonti 1.1
<syntaxhighlight lang="phixmonti">0 tolist var r
 
def append
r swap 0 put var r
enddef
 
"-6,-3--1,3-5,7-11,14,15,17-20" "," " " subst split
 
len for
get dup tonum dup
nan == if
drop
dup len 1 - 2 swap slice
"-" find dup 2 + rot drop
rot rot 1 swap slice tonum
rot rot len rot swap over - 1 + slice tonum
nip rot drop
2 tolist for append endfor
else
append drop
endif
endfor
r
pstack</syntaxhighlight>
 
Other solution
<syntaxhighlight lang="phixmonti">0 tolist var r
 
def append
r swap 0 put var r
enddef
 
"-6,-3--1,3-5,7-11,14,15,17-20" "," " " subst split
 
len for
get dup tonum dup
nan == if
drop
dup 32 1 set
"-" find nip
swap over 1 - 1 swap slice tonum
rot rot len rot swap over - swap 1 + swap slice tonum
nip 2 tolist for append endfor
else
append drop
endif
endfor
r
pstack</syntaxhighlight>
 
A bit more understandable
<syntaxhighlight lang="phixmonti">0 tolist var r
 
def append
r swap 0 put var r
enddef
 
def getSeparator /# s -- s n #/
dup 32 1 set
"-" find nip
enddef
 
def first /# s n -- s n #/
swap over 1 - 1
swap slice tonum
enddef
 
def last /# s n -- s n #/
swap len rot swap over - swap 1 +
swap slice tonum
enddef
 
"-6,-3--1,3-5,7-11,14,15,17-20" "," " " subst split
 
len for
get dup tonum dup
nan == if
drop
getSeparator
first
rot rot swap
last
nip 2 tolist for append endfor
else
append drop
endif
endfor
r
pstack</syntaxhighlight>
 
=={{header|PHP}}==
{{trans|Python}}
<langsyntaxhighlight PHPlang="php">function rangex($str) {
$lst = array();
foreach (explode(',', $str) as $e) {
Line 1,902 ⟶ 3,204:
}
return $lst;
}</langsyntaxhighlight>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de rangeexpand (Str)
(make
(for S (split (chop Str) ",")
Line 1,913 ⟶ 3,215:
(format (head @ S))
(format (tail (- -1 @) S)) ) )
(link (format S)) ) ) ) )</langsyntaxhighlight>
{{out}}
<pre>: (rangeexpand "-6,-3--1,3-5,7-11,14,15,17-20")
Line 1,919 ⟶ 3,221:
 
=={{header|PL/I}}==
<langsyntaxhighlight PLlang="pl/Ii">range_expansion:
procedure options (main);
 
Line 1,969 ⟶ 3,271:
delimiter = ',';
end;
end range_expansion;</langsyntaxhighlight>
{{out}}
<pre>
Line 1,976 ⟶ 3,278:
 
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
<lang PowerShell>
function range-expansion($array) {
function expansion($arr) {
Line 1,999 ⟶ 3,301:
}
range-expansion "-6,-3--1,3-5,7-11,14,15,17-20"
</syntaxhighlight>
</lang>
<b>Output:</b>
<pre>
-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
</pre>
 
===Alternate Half-Assed Regex Version===
Ten times faster (only minimally tested).
<syntaxhighlight lang="powershell">
function Expand-Range
{
[CmdletBinding()]
[OutputType([int])]
Param
(
[Parameter(Mandatory=$true,
Position=0)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^[0-9,-]*$')]
[string]
$Range
)
 
try
{
if ($Range -match '-,') # I'm not good enough to weed this case out with Regex
{
throw "Input string was not in a correct format."
}
 
[int[]]$output = $Range -split ',' | ForEach-Object {
 
[int[]]$array = $_ -split '(?<=\d)-'
 
if ($array.Count -gt 1) # $array contains one or two elements
{
$array[0]..$array[1] # two elements = start and end of range
}
else
{
$array # one element = an integer
}
}
}
catch
{
throw "Input string was not in a correct format."
}
 
$output
}
</syntaxhighlight>
<syntaxhighlight lang="powershell">
(Expand-Range "-6,-3--1,3-5,7-11,14,15,17-20") -join ", "
</syntaxhighlight>
{{Out}}
<pre>
-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20
Line 2,010 ⟶ 3,366:
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.
<langsyntaxhighlight Prologlang="prolog">range_expand :-
L = '-6,-3--1,3-5,7-11,14,15,17-20',
writeln(L),
Line 2,090 ⟶ 3,446:
run(Var1,LRest,[Deb, Fin], RRest).
 
run(Val,[Other|RRest], [Val, Val],[Other|RRest]).</langsyntaxhighlight>
{{out}}
<pre> ?- range_expand.
Line 2,098 ⟶ 3,454:
 
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">Procedure rangeexpand(txt.s, List outputList())
Protected rangesCount = CountString(txt, ",") + 1
Protected subTxt.s, r, rangeMarker, rangeStart, rangeFinish, rangeIncrement, i
Line 2,143 ⟶ 3,499:
Input()
CloseConsole()
EndIf</langsyntaxhighlight>
{{out}}
<pre>[ -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 ]</pre>
 
=={{header|Python}}==
===Procedural===
<lang python>def rangeexpand(txt):
<syntaxhighlight lang="python">def rangeexpand(txt):
lst = []
for r in txt.split(','):
Line 2,158 ⟶ 3,515:
return lst
 
print(rangeexpand('-6,-3--1,3-5,7-11,14,15,17-20'))</langsyntaxhighlight>
 
Anotheranother variant, using [[regular expressions]] to parse the ranges:,
<langsyntaxhighlight lang="python">import re
 
def rangeexpand(txt):
Line 2,171 ⟶ 3,528:
else:
lst.append(int(start))
return lst</langsyntaxhighlight>
 
{{out}}
===Functional===
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
As a fold/catamorphism:
{{Works with|Python|3.7}}
<syntaxhighlight lang="python">'''Range expansion'''
 
from functools import (reduce)
 
 
# ------------------- EXPANSION FUNCTION -------------------
 
# rangeExpansion :: String -> [Int]
def rangeExpansion(s):
'''List of integers expanded from a
comma-delimited string of individual
numbers and hyphenated ranges.
'''
def go(a, x):
tpl = breakOn('-')(x[1:])
r = tpl[1]
return a + (
[int(x)] if not r
else enumFromTo(int(x[0] + tpl[0]))(
int(r[1:])
)
)
return reduce(go, s.split(','), [])
 
 
# -------------------------- TEST --------------------------
def main():
'''Expansion test'''
 
print(
fTable(__doc__ + ':')(
lambda x: "\n'" + str(x) + "'"
)(lambda x: '\n\n\t' + showList(x))(
rangeExpansion
)([
'-6,-3--1,3-5,7-11,14,15,17-20'
])
)
 
 
# ------------------- GENERIC FUNCTIONS --------------------
 
# breakOn :: String -> String -> (String, String)
def breakOn(needle):
'''A tuple of:
1. the prefix of haystack before needle,
2. the remainder of haystack, starting
with needle.
'''
def go(haystack):
xs = haystack.split(needle)
return (xs[0], haystack[len(xs[0]):]) if (
1 < len(xs)
) else (haystack, '')
return lambda haystack: go(haystack) if (
needle
) else None
 
 
# enumFromTo :: Int -> Int -> [Int]
def enumFromTo(m):
'''Enumeration of integer values [m..n]
'''
return lambda n: list(range(m, 1 + n))
 
 
# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
'''Heading -> x display function ->
fx display function -> f -> xs -> tabular string.
'''
def gox(xShow):
def gofx(fxShow):
def gof(f):
def goxs(xs):
ys = [xShow(x) for x in xs]
w = max(map(len, ys))
 
def arrowed(x, y):
return y.rjust(w, ' ') + ' -> ' + (
fxShow(f(x))
)
return s + '\n' + '\n'.join(
map(arrowed, xs, ys)
)
return goxs
return gof
return gofx
return gox
 
 
# showList :: [a] -> String
def showList(xs):
'''Stringification of a list.
'''
return '[' + ','.join(str(x) for x in xs) + ']'
 
 
# MAIN ---
if __name__ == '__main__':
main()</syntaxhighlight>
{{Out}}
<pre>Range expansion:
 
'-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>
 
=={{header|R}}==
<syntaxhighlight lang="r">
<lang R>
rangeExpand <- function(text) {
lst <- gsub("(\\d)-", "\\1:", unlist(strsplit(text, ",")))
Line 2,184 ⟶ 3,651:
rangeExpand("-6,-3--1,3-5,7-11,14,15,17-20")
[1] -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20
</syntaxhighlight>
</lang>
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 2,201 ⟶ 3,668:
 
(range-expand "-6,-3--1,3-5,7-11,14,15,17-20")
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,212 ⟶ 3,679:
rather than 3 followed by - followed by -4,
a readtable is installed that makes - a delimiter.
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 2,239 ⟶ 3,706:
(range-expand (open-input-string "-6,-3--1,3-5,7-11,14,15,17-20"))
</syntaxhighlight>
</lang>
Note that one can use the full number syntax in this alternative version:
<pre>
Line 2,245 ⟶ 3,712:
'(1 2 30.0 31.0 32.0)
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
 
{{works with|Rakudo|2016.07}}
<syntaxhighlight lang="raku" line>sub range-expand (Str $range-description) {
my token number { '-'? \d+ }
my token range { (<&number>) '-' (<&number>) }
$range-description
.split(',')
.map({ .match(&range) ?? $0..$1 !! +$_ })
.flat
}
say range-expand('-6,-3--1,3-5,7-11,14,15,17-20').join(', ');</syntaxhighlight>
 
{{out}}
<pre>-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20</pre>
 
<br>
Alternatively, using a grammar:
 
<syntaxhighlight lang="raku" line>grammar RangeList {
token TOP { <term>* % ',' { make $<term>.map(*.made) } }
token term { [<range>|<num>] { make ($<num> // $<range>).made } }
token range { <num> '-' <num> { make +$<num>[0] .. +$<num>[1] } }
token num { '-'? \d+ { make +$/ } }
}
 
say RangeList.parse('-6,-3--1,3-5,7-11,14,15,17-20').made.flat.join(', ');</syntaxhighlight>
 
{{out}}
<pre>-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20</pre>
 
=={{header|Raven}}==
Based loosely on Ruby
<langsyntaxhighlight lang="raven">define get_num use $lst
# "-22" split by "-" is [ "", "22" ] so check if
# first list item is "" -> a negative number
Line 2,280 ⟶ 3,781:
"\n" print
 
'-6,-3--1,3-5,7-11,14,15,17-20' range_expand</langsyntaxhighlight>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
Line 2,286 ⟶ 3,787:
=={{header|REXX}}==
===version 1===
Extra (imbedded) blanks were added to the original&nbsp; old &nbsp; list (which are ignored) to make anthe &nbsp; ''over/under'' &nbsp; comparison easier &nbsp; (in the output).
<langsyntaxhighlight lang="rexx">/*REXX program expands an ordered list of integers into an expanded list. */
old= '-6,-3--1, 3-5, 7-11, 14,15,17-20'; a=translate(old,,',')
new= /*translate , ───► blanks /*translate [↑] commas (,) ───► blanks*/
do until a==''; parse var a X a /*obtain the next integer ─or───or── range.*/
p=pos('-', X, 2) /*find the location of a dash (maybe). */
if p==0 then new=new X /*append integer X to the new list.*/
else do j=left(X,p-1) to substr(X,p+1); new=new j
end /*j*/ /*append a single int[↑] integer at a time [↑]*/
end /*until*/
/*stick a fork in it, we're all done. */
new=translate( strip(new), ',', ," ") /*remove the first blank, add commas. */
say 'old list: ' old /*show the old list of numbers/ranges.*/
say 'new list: ' new /*show the " " new list of" " numbers. */</langsyntaxhighlight>
'''output'''
{{out}}
<pre>
old list: -6,-3--1, 3-5, 7-11, 14,15,17-20
Line 2,307 ⟶ 3,808:
 
===Version 2 somewhat simplified !?!===
<langsyntaxhighlight lang="rexx">/*REXX program to expand a range of integers into a list. *************
* 09.08.2012 Walter Pachl
**********************************************************************/
Line 2,335 ⟶ 3,836:
End
End
Say 'new='new /*show the expanded list */</langsyntaxhighlight>
{{out}}
<pre>
old=-6,-3--1,3-5,7-11,14,15,17-20
new=-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
</pre>
 
=={{header|Ring}}==
<syntaxhighlight lang="ring">
# Project : Range expansion
 
int = "-6,-3--1,3-5,7-11,14,15,17-20"
int = str2list(substr(int, ",", nl))
newint = []
for n=1 to len(int)
nrint = substr(int[n], "-")
nrint2 = substr(int[n], "--")
if nrint2 > 0
temp1 = left(int[n], nrint2 -1)
temp2 = right(int[n], len(int[n]) - nrint2)
add(newint, [temp1,temp2])
else
if len(int[n]) <= 2
add(newint, [int[n], ""])
else
if nrint > 0 and nrint2 = 0
temp1 = left(int[n], nrint - 1)
temp2 = right(int[n], len(int[n]) - nrint)
add(newint, [temp1,temp2])
ok
ok
ok
next
showarray(newint)
 
func showarray(vect)
see "["
svect = ""
for n = 1 to len(vect)
if newint[n][2] != ""
for nr = newint[n][1] to newint[n][2]
svect = svect +"" + nr + ", "
next
else
svect = svect +"" + newint[n][1] + ", "
ok
next
svect = left(svect, len(svect) - 2)
see svect
see "]" + nl
</syntaxhighlight>
Output:
<pre>
[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]
</pre>
 
=={{header|RPL}}==
{{works with|RPL|HP48-R}}
« → in
« <span style="color:grey">''@ Tokenizing the string''</span>
"{" 1 in SIZE '''FOR''' j
in j DUP SUB
'''IF''' DUP "-" == '''THEN'''
'''IF''' in j 1 - DUP SUB "0" ≥ '''THEN''' DROP " TO " '''END'''
'''END'''
+
'''NEXT'''
<span style="color:grey">''@ Expanding ranges''</span>
OBJ→ 'in' STO { }
1 in SIZE '''FOR''' j
in j GET
'''IF''' DUP 'TO' SAME '''THEN'''
DROP « n » 'n' in j 1 - GET 1 + in 'j' INCR GET 1 SEQ
'''END'''
+
'''NEXT'''
» » '<span style="color:blue">RNG→</span>' STO
 
"-6,-3--1,3-5,7-11,14,15,17-20" <span style="color:blue">RNG→</span>{{out}}
<pre>
1: { -6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20 }
</pre>
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">def range_expand(rng)
rng.split(',').flat_map do |part|
if part =~ /^(-?\d+)-(-?\d+)$/
Line 2,353 ⟶ 3,930:
end
 
p range_expand('-6,-3--1,3-5,7-11,14,15,17-20')</langsyntaxhighlight>
{{out}}
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]</pre>
 
=={{header|Run BASIC}}==
<langsyntaxhighlight lang="runbasic">PRINT rangeExpand$("-6,-3--1,3-5,7-11,14,15,17-20")
end
 
Line 2,382 ⟶ 3,959:
if i <> 0 then goto [loop]
rangeExpand$ = range$
end function</langsyntaxhighlight>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
Line 2,389 ⟶ 3,966:
Rust doesn't have regex in standard library yet.
 
<langsyntaxhighlight lang="rust">use std::str::FromStr;
 
// Precondition: range doesn't contain multibyte UTF-8 characters
Line 2,415 ⟶ 3,992:
println!("{:?}", range_expand("-6,-3--1,3-5,7-11,14,15,17-20"));
}
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,421 ⟶ 3,998:
<pre>[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]
</pre>
 
=={{header|S-lang}}==
<syntaxhighlight lang="s-lang">variable r_expres = "-6,-3--1,3-5,7-11,14,15,17-20", s, r_expan = {}, dpos, i;
 
foreach s (strchop(r_expres, ',', 0))
{
% S-Lang built-in RE's are fairly limited, and have a quirk:
% grouping is done with \\( and \\), not ( and )
% [PCRE and Oniguruma RE's are available via standard libraries]
if (string_match(s, "-?[0-9]+\\(-\\)-?[0-9]+", 1)) {
(dpos, ) = string_match_nth(1);
 
% Create/loop-over a "range array": from num before - to num after it:
foreach i ( [integer(substr(s, 1, dpos)) : integer(substr(s, dpos+2, -1))] )
list_append(r_expan, string(i));
}
else
list_append(r_expan, s);
}
print(strjoin(list_to_array(r_expan), ", "));</syntaxhighlight>
 
=={{header|Scala}}==
<langsyntaxhighlight Scalalang="scala">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
}</langsyntaxhighlight>
 
{{out}}
Line 2,437 ⟶ 4,035:
 
=={{header|Scheme}}==
<langsyntaxhighlight lang="scheme">(define split
(lambda (str char skip count)
(let ((len (string-length str)))
Line 2,471 ⟶ 4,069:
(display ","))))))
(split str #\, 0 0))
(newline)))</langsyntaxhighlight>
{{out}}
<pre>
Line 2,481 ⟶ 4,079:
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.
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.
<langsyntaxhighlight lang="seed7">$ include "seed7_05.s7i";
include "scanstri.s7i";
 
Line 2,515 ⟶ 4,113:
end for;
writeln;
end func;</langsyntaxhighlight>
{{out}}
<pre>
Line 2,522 ⟶ 4,120:
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">func rangex(str) {
str.split(',').map { |ranger|
var matchm = ranger.match(/^
(?(DEFINE) (?<int>[+-]?[0-9]+) )
(?<from>(?&int))-(?<to>(?&int))
$/x)
m ? do {var c = m.ncap; (Num(c{:from}) .. Num(c{:to}))...}
) -> is_successful ? (
: var ncap = match.ncap;Num(r)
ncap[:from].to_i .. ncap[:to].to_i;
) : range.to_i;
}
}
 
say rangex('-6,-3--1,3-5,7-11,14,15,17-20').join(',')</syntaxhighlight>
# Test and display
say rangex('-6,-3--1,3-5,7-11,14,15,17-20').flatten.join(',');</lang>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
 
=={{header|SNOBOL4}}==
<langsyntaxhighlight SNOBOL4lang="snobol4">* # Return range n1 .. n2
define('range(n1,n2)') :(range_end)
range range = range n1 ','; n1 = lt(n1,n2) n1 + 1 :s(range)
Line 2,555 ⟶ 4,150:
* # Test and display
output = rangex('-6,-3--1,3-5,7-11,14,15,17-20')
end</langsyntaxhighlight>
{{out}}
<pre>-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20</pre>
=={{header|SQL}}==
{{works with|ORACLE 19c}}
This is not a particularly efficient solution, but it gets the job done.
 
<syntaxhighlight lang="sql">
/*
This code is an implementation of "Range expansion" in SQL ORACLE 19c
p_list_of_sets -- input string
delimeter by default ","
*/
with
function range_expansion(p_list_of_sets in varchar2)
return varchar2 is
--
v_list_of_sets varchar2(32767) := p_list_of_sets;
v_output varchar2(32767) ;
v_set_1 varchar2(2000) ;
v_set_1_min pls_integer;
v_set_1_max pls_integer;
--
function sort_set(p_in_str varchar2)
return varchar2 is
v_out varchar2(32767) := p_in_str;
begin
--
with out_tab as
(select to_number(regexp_substr(str, '[^,]+', 1, rownum, 'c', 0) default null on conversion error) elem
from
(select p_in_str as str
from dual
)
connect by level <= regexp_count(str, '[^,]+')
)
select trim(both ',' from min(elem)||','||max(elem)) end
into v_out
from out_tab;
--
return v_out;
end;
--
function sort_output(p_in_str varchar2)
return varchar2 is
v_out varchar2(32767) := p_in_str;
begin
--
with out_tab as
(select distinct to_number(regexp_substr(str, '[^,]+', 1, rownum, 'c', 0) default null on conversion error) elem
from
(select p_in_str as str
from dual
)
connect by level <= regexp_count(str, '[^,]+')
)
select listagg(elem, ',') within group(order by elem) end
into v_out
from out_tab
where elem is not null;
--
return v_out;
end;
--
begin
--cleaning
v_list_of_sets := replace(v_list_of_sets, ' ', '') ;
v_list_of_sets := replace(v_list_of_sets, '+', '') ;
v_list_of_sets := replace(v_list_of_sets, ',', '|') ;
v_list_of_sets := regexp_replace(v_list_of_sets, '(\d{1,})-(\d{1,})', '\1,\2', 1, 0) ;
v_list_of_sets := regexp_replace(v_list_of_sets, '(\d{1,})--(\d{1,})', '\1,-\2', 1, 0) ;
--
<<loop_through_sets>>
while regexp_count(v_list_of_sets, '[^|]+') > 0
loop
v_set_1 := regexp_substr(v_list_of_sets, '[^|]+', 1, 1) ;
v_list_of_sets := regexp_replace(v_list_of_sets, v_set_1, sort_set(v_set_1), 1, 1) ;
v_set_1 := sort_set(v_set_1) ;
--
continue loop_through_sets when v_set_1 is null;
--
v_set_1_min := least(to_number(regexp_substr(v_set_1, '[^,]+', 1, 1))
,to_number(regexp_substr(v_set_1, '[^,]+', 1, 2))
) ;
v_set_1_max := greatest(to_number(regexp_substr(v_set_1, '[^,]+', 1, 1))
,to_number(regexp_substr(v_set_1, '[^,]+', 1, 2))
) ;
--
<<loop_for>>
for i in v_set_1_min..v_set_1_max
loop
--
v_output := v_output||','||i;
--
end loop loop_for;
--
v_list_of_sets := regexp_replace(v_list_of_sets,v_set_1,'',1,1);
--
end loop loop_through_sets;
--
v_output := sort_output(v_output);
--
return trim(v_output);
end;
 
--Test
select '-- Test ' as output from dual
union all
select lpad(' ', 65) || ' ==> ' || range_expansion(' ') as output from dual
union all
select lpad('-0,+0,-2 ,-1--2,3 ,-3, 2,-2', 65) || ' ==> ' || range_expansion('-0,+0,-2 ,-1--2,3 ,-3, 2,-2') as output from dual
union all
select lpad('0,-1,+2,-2', 65) || ' ==> ' || range_expansion('0,-1,2,-2') as output from dual
union all
select lpad('-D,-w23--1,+14q,15,17-20,3-5,7-11, +0, 2q, +4, 3,0 ,-0,-2 , -3', 65) || ' ==> ' || range_expansion('-D,-w23--1,+14q,15,17-20,3-5,7-11, +0, 2q, +4, 3,0 ,-0,-2 , -3') as output from dual
union all
select lpad('-6,-3--1,14,15,17-20,3-5,7-11', 65) || ' ==> ' || range_expansion('-6,-3--1,14,15,17-20,3-5,11-7') as output from dual
union all
--Test RosettaCode
select '-- Test RosettaCode' as output from dual
union all
select lpad('-6,-3--1,3-5,7-11,14,15,17-20', 65) || ' ==> ' || range_expansion('-6,-3--1,3-5,7-11,14,15,17-20') as output from dual
;
 
</syntaxhighlight>
 
{{out}}
<pre>
-- Test
==>
-0,+0,-2 ,-1--2,3 ,-3, 2,-2 ==> -3,-2,-1,0,2,3
0,-1,+2,-2 ==> -2,-1,0,2
-D,-w23--1,+14q,15,17-20,3-5,7-11, +0, 2q, +4, 3,0 ,-0,-2 , -3 ==> -3,-2,-1,0,3,4,5,7,8,9,10,11,15,17,18,19,20
-6,-3--1,14,15,17-20,3-5,7-11 ==> -6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20
-- Test RosettaCode
-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>
 
=={{header|Tailspin}}==
<syntaxhighlight lang="tailspin">
composer expand
[<element>*]
rule element: <range|INT> (<','>?)
rule range: (def start: <INT>; <'-'>) <INT> -> $start..$
end expand
 
'-6,-3--1,3-5,7-11,14,15,17-20' -> expand -> !OUT::write
</syntaxhighlight>
{{out}}
<pre>
[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]
</pre>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">proc rangeExpand desc {
set result {}
foreach term [split $desc ","] {
Line 2,573 ⟶ 4,317:
}
 
puts [rangeExpand "-6,-3--1,3-5,7-11,14,15,17-20"]</langsyntaxhighlight>
{{out}}
<pre>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</pre>
 
=={{header|TUSCRIPT}}==
<langsyntaxhighlight lang="tuscript">$$ MODE TUSCRIPT
rangednrs="-6,-3--1,3-5,7-11,14,15,17-20"
expandnrs=SPLIT (rangednrs,":,:")
Line 2,599 ⟶ 4,343:
expandnrs= JOIN (expandnrs,",")
 
PRINT expandnrs</langsyntaxhighlight>
{{out}}
<pre>
Line 2,624 ⟶ 4,368:
Code:
 
<langsyntaxhighlight lang="txr">@(define num (n))@(local tok)@{tok /[+\-]?\d+/}@(bind n @(int-str tok))@(end)
@(define entry (e))@\
@(local n1 n2)@\
Line 2,656 ⟶ 4,400:
(rangeexpand (rest list))))
(t (cons (first list) (rangeexpand (rest list))))))
 
(defun sortdup (li)
(let ((h [group-by identity li]))
[sort (hash-keys h) <]))
 
(defun rangeexpand (list)
(sortdupuniq (expand-helper list))))
@(repeat)
@(rangelist x)@{trailing-junk}
Line 2,670 ⟶ 4,410:
your junk: @{trailing-junk}
@(end)
@(end)</langsyntaxhighlight>
 
{{out|Run}}
Line 2,694 ⟶ 4,434:
=={{header|UNIX Shell}}==
{{works with|bash}}
<langsyntaxhighlight lang="bash">#!/usr/bin/bash
 
range_expand () (
Line 2,712 ⟶ 4,452:
)
 
range_expand "-6,-3--1,3-5,7-11,14,15,17-20"</langsyntaxhighlight>
{{out}}
<pre>-6 -3 -2 -1 3 4 5 7 8 9 10 11 14 15 17 18 19 20</pre>
 
=={{header|Ursala}}==
<langsyntaxhighlight Ursalalang="ursala">#import std
#import int
 
Line 2,724 ⟶ 4,464:
#cast %zL
 
t = rex '-6,-3--1,3-5,7-11,14,15,17-20'</langsyntaxhighlight>
{{out}}
<pre><-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20></pre>
 
=={{header|VBA}}==
<langsyntaxhighlight VBAlang="vba">Public Function RangeExpand(AString as string)
' return a list with the numbers expressed in AString
Dim Splits() As String
Line 2,774 ⟶ 4,514:
Next
Debug.Print
End Sub</langsyntaxhighlight>
{{out}}
<pre>
Line 2,782 ⟶ 4,522:
</pre>
 
=={{header|XPL0Wren}}==
{{trans|Kotlin}}
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations
<syntaxhighlight lang="wren">var expandRange = Fn.new { |s|
string 0; \use zero-terminated strings, instead of MSb
var list = []
char Str;
var items = s.split(",")
int Char, Inx;
for (item in items) {
var count = item.count { |c| c == "-" }
if (count == 0 || (count == 1 && item[0] == "-")) {
list.add(Num.fromString(item))
} else {
var items2 = item.split("-")
var first
var last
if (count == 1) {
first = Num.fromString(items2[0])
last = Num.fromString(items2[1])
} else if (count == 2) {
first = Num.fromString(items2[1]) * -1
last = Num.fromString(items2[2])
} else {
first = Num.fromString(items2[1]) * -1
last = Num.fromString(items2[3]) * -1
}
for (i in first..last) list.add(i)
}
}
return list
}
 
var s = "-6,-3--1,3-5,7-11,14,15,17-20"
System.print(expandRange.call(s))</syntaxhighlight>
 
{{out}}
proc GetCh; \Get character from Str
<pre>
[Char:= Str(Inx);
[-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]
Inx:= Inx+1;
</pre>
]; \GetCh
 
=={{header|XPL0}}==
 
See Range Extraction for explanations.
func GetNum; \Get number from Str and return its value
<syntaxhighlight lang "XPL0">proc Expand(Range);
int Neg, Num;
char Range;
[Neg:= false;
int Lo, Hi, N;
if Char = ^- then [Neg:= true; GetCh];
[Text(8, Range);
Num:= 0;
loop [Lo:= IntIn(8);
while Char>=^0 & Char<=^9 do
BackUp; \get what terminated number
[Num:= Num*10 + Char-^0;
GetCh;case ChIn(8) of
^-: [Hi:= IntIn(8);
for N:= Lo to Hi do
[IntOut(0, N);
if N < Hi then Text(0, ", ");
];
BackUp;
if ChIn(8) = $1A \EOF\ then quit;
];
^,: IntOut(0, Lo)
other \EOF\ [IntOut(0, Lo); quit];
Text(0, ", ");
];
];
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>
 
Expand("-6,-3--1,3-5,7-11,14,15,17-20")
</syntaxhighlight>
{{out}}
<pre>
-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20</pre>
 
</pre>
=={{header|Yabasic}}==
<syntaxhighlight lang="yabasic">print RangeExpand$("-6,-3--1,3-5,7-11,14,15,17-20")
 
sub RangeExpand$(s$)
local w$(1), n, i, r$, p, a, b
n = token(s$, w$(), ",")
for i = 1 to n
p = instr(w$(i), "-", 2)
if p then
a = val(left$(w$(i), p-1))
b = val(right$(w$(i), len(w$(i)) - p))
repeat
r$ = r$ + str$(a) + ","
a = a + 1
until(a > b)
else
r$ = r$ + w$(i) + ","
end if
next
return left$(r$, len(r$) - 1)
end sub
</syntaxhighlight>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl">fcn rangex(s){
fcn(s,re){
if (re.search(s)){
Line 2,842 ⟶ 4,624:
s.split(",").pump(List, _.fp1(RegExp(0'|(.*\d+)-(.*\d+)|)))
.flatten().concat(",");
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">ns="-6,-3-1,3-5,7-11,14,15,17-20";
rangex(ns).println();
 
ns="-6,-3--1,3-5,7-11,14,15,17-20";
rangex(ns).println();</langsyntaxhighlight>
 
{{out}}
1,150

edits