Brace expansion using ranges: Difference between revisions
→{{header|jq}}: right-most-first
(Added a Python implementation) |
(→{{header|jq}}: right-most-first) |
||
(24 intermediate revisions by 10 users not shown) | |||
Line 1:
{{draft task}}{{clarified-review}}
;Task
Write and test a function which expands one or more Unix-style '''numeric and alphabetic range braces''' embedded in a larger string.<br><br>
Line 54:
{{task heading|Tests}}
Generate and display here the expansion of (at least) each of the
The JavaScript implementation below uses parser combinators, aiming to encode a more or less full and legible description of the <pre><PREAMBLE><AMBLE><POSTSCRIPT></pre> range brace grammar, but you should use any resource that suggests itself in your language, including parser libraries.
Line 60:
(The grammar of range expansion, unlike that of nested list expansion, is not recursive, so even regular expressions should prove serviceable here).
The output of the JS implementation, which aims to match the brace expansion behaviour of the default '''zsh''' shell on
<pre>simpleNumberRising{1..3}.txt ->
Line 81:
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
reverseSteppedNumberRising{1..6..-2}.txt ->
reverseSteppedNumberRising5.txt
reverseSteppedNumberRising3.txt
reverseSteppedNumberRising1.txt
combined-{Q..P}{2..1}.txt ->
Line 106 ⟶ 111:
* [[Range_expansion|range expansion]]
<br><br>
=={{header|11l}}==
{{trans|Nim}}
<syntaxhighlight lang="11l">F intFromString(s) -> Int?
X.try
R Int(s)
X.catch ValueError
R N
F parseRange(r)
I r.empty {R [‘{}’]}
V sp = r.split(‘..’)
I sp.len == 1 {R [‘{’r‘}’]}
V first = sp[0]
V last = sp[1]
V incr = I sp.len == 2 {‘1’} E sp[2]
Int? val1 = intFromString(first)
Int? val2 = intFromString(last)
Int? val3 = intFromString(incr)
I val3 == N {R [‘{’r‘}’]}
V n3 = val3
V numeric = val1 != N & val2 != N
Int n1
Int n2
I numeric
n1 = val1
n2 = val2
E
I (val1 != N & val2 == N) | (val1 == N & val2 != N)
R [‘{’r‘}’]
I first.len != 1 | last.len != 1
R [‘{’r‘}’]
n1 = first[0].code
n2 = last[0].code
V width = 1
I numeric
width = max(first.len, last.len)
I n3 == 0
R I numeric {[String(n1).zfill(width)]} E [first]
V asc = n1 < n2
I n3 < 0
asc = !asc
swap(&n1, &n2)
n3 = -n3
[String] result
V i = n1
I asc
L i <= n2
result.append(I numeric {String(i).zfill(width)} E Char(code' i))
i += n3
E
L i >= n2
result.append(I numeric {String(i).zfill(width)} E Char(code' i))
i -= n3
R result
F rangeExpand(s)
V result = [‘’]
V rng = ‘’
V inRng = 0B
L(c) s
I c == ‘{’ & !inRng
inRng = 1B
rng = ‘’
E I c == ‘}’ & inRng
V rngRes = parseRange(rng)
[String] res
L(r) result
L(rr) rngRes
res.append(r‘’rr)
result = move(res)
inRng = 0B
E I inRng
rng ‘’= c
E
L(&s) result
s ‘’= c
I inRng
L(&s) result
s ‘’= ‘{’rng
R result
-V examples = [‘simpleNumberRising{1..3}.txt’,
‘simpleAlphaDescending-{Z..X}.txt’,
‘steppedDownAndPadded-{10..00..5}.txt’,
‘minusSignFlipsSequence {030..20..-5}.txt’,
‘combined-{Q..P}{2..1}.txt’,
‘li{teral’,
‘rangeless{}empty’,
‘rangeless{random}string’,
‘mixedNumberAlpha{5..k}’,
‘steppedAlphaRising{P..Z..2}.txt’,
‘stops after endpoint-{02..10..3}.txt’]
L(s) examples
print(s" ->\n ", end' ‘’)
V res = rangeExpand(s)
print(res.join("\n "))
print()</syntaxhighlight>
{{out}}
<pre>
simpleNumberRising{1..3}.txt ->
simpleNumberRising1.txt
simpleNumberRising2.txt
simpleNumberRising3.txt
simpleAlphaDescending-{Z..X}.txt ->
simpleAlphaDescending-Z.txt
simpleAlphaDescending-Y.txt
simpleAlphaDescending-X.txt
steppedDownAndPadded-{10..00..5}.txt ->
steppedDownAndPadded-10.txt
steppedDownAndPadded-05.txt
steppedDownAndPadded-00.txt
minusSignFlipsSequence {030..20..-5}.txt ->
minusSignFlipsSequence 020.txt
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
combined-{Q..P}{2..1}.txt ->
combined-Q2.txt
combined-Q1.txt
combined-P2.txt
combined-P1.txt
li{teral ->
li{teral
rangeless{}empty ->
rangeless{}empty
rangeless{random}string ->
rangeless{random}string
mixedNumberAlpha{5..k} ->
mixedNumberAlpha{5..k}
steppedAlphaRising{P..Z..2}.txt ->
steppedAlphaRisingP.txt
steppedAlphaRisingR.txt
steppedAlphaRisingT.txt
steppedAlphaRisingV.txt
steppedAlphaRisingX.txt
steppedAlphaRisingZ.txt
stops after endpoint-{02..10..3}.txt ->
stops after endpoint-02.txt
stops after endpoint-05.txt
stops after endpoint-08.txt
</pre>
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">Brace_expansion_using_ranges(line){
needle := "^.*\K{(?P<Start>[^{}]+?)\..(?P<End>[^{}]+?)(?:\..(?P<Incr>[^{}]+?))?}"
while true
{
while pos := RegExMatch(line, needle, m, A_Index=1?1:pos+StrLen(m))
{
char := false, step := "", output := ""
reverse := InStr(mIncr, "-") ? true : false
if mStart is number
pad1 := pad(mStart), pad2 := pad(mEnd), pad := StrLen(pad1)>=StrLen(pad2) ? pad1 : pad2
else
mStart := Ord(mStart), mEnd := Ord(mEnd), char := true
mIncr := (mIncr?Abs(mIncr):1) * (mStart>mEnd?-1:1)
loop % Abs((mStart-mEnd)/mIncr) + 1
{
step := mStart + (A_Index-1) * mIncr
step := pad <> "" ? SubStr(pad . step, 1-StrLen(pad)) : step
step := char ? Chr(step) : step
Rep := StrReplace(line, m, step)
output := reverse ? rep "`n" output : output .= Rep "`n"
}
output := Trim(Output, "`n")
}
if RegExMatch(output, needle)
line := output
else
break
}
return output ? output : line
}
pad(num){
if RegExMatch(num, "`am)^(0+)(?=[1-9]|0$)", m)
loop % StrLen(num)
pad .= "0"
return pad
}</syntaxhighlight>
Examples:<syntaxhighlight lang="autohotkey">data=
(
simpleNumberRising{1..3}.txt
simpleAlphaDescending-{Z..X}.txt
steppedDownAndPadded-{10..00..5}.txt
minusSignFlipsSequence {030..20..-5}.txt
reverseSteppedNumberRising{1..6..-2}.txt
combined-{Q..P}{2..1}.txt
emoji{🌵..🌶}{🌽..🌾}etc
li{teral
rangeless{}empty
rangeless{random}string
)
for i, line in StrSplit(data, "`n", "`r")
result .= line " ->`n" RegExReplace(Brace_expansion_using_ranges(line), "`am)^", "`t") "`n`n"
MsgBox, 262144, , % result
return</syntaxhighlight>
{{out}}
<pre>simpleNumberRising{1..3}.txt ->
simpleNumberRising1.txt
simpleNumberRising2.txt
simpleNumberRising3.txt
simpleAlphaDescending-{Z..X}.txt ->
simpleAlphaDescending-Z.txt
simpleAlphaDescending-Y.txt
simpleAlphaDescending-X.txt
steppedDownAndPadded-{10..00..5}.txt ->
steppedDownAndPadded-10.txt
steppedDownAndPadded-05.txt
steppedDownAndPadded-00.txt
minusSignFlipsSequence {030..20..-5}.txt ->
minusSignFlipsSequence 020.txt
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
reverseSteppedNumberRising{1..6..-2}.txt ->
reverseSteppedNumberRising5.txt
reverseSteppedNumberRising3.txt
reverseSteppedNumberRising1.txt
combined-{Q..P}{2..1}.txt ->
combined-Q2.txt
combined-Q1.txt
combined-P2.txt
combined-P1.txt
emoji{🌵..🌶}{🌽..🌾}etc ->
emoji🌵🌽etc
emoji🌵🌾etc
emoji🌶🌽etc
emoji🌶🌾etc
li{teral ->
li{teral
rangeless{}empty ->
rangeless{}empty
rangeless{random}string ->
rangeless{random}string</pre>
=={{header|F_Sharp|F#}}==
<syntaxhighlight lang="fsharp">
// Brace expansion using ranges. Nigel Galloway: October 6th., 2021
let fUC, fUR=System.Text.Rune.GetUnicodeCategory,(fun n->System.Text.Rune.GetRuneAt(n,0))
let fV(n,i,g,e,l,s)=let l=if l="" then 1 else int l in match l with 0->None |_->Some(n,i,g,e,int l,s)
let(|Valid|_|)(n:System.Text.RegularExpressions.Match)=let fN(g:string)=n.Groups.[g].Value in if n.Success then fV(fN "n",fN "i",fN "g",fN "e",fN "l",fN "s") else None
let fN(g:string)=let mutable g=g.EnumerateRunes() in if g.MoveNext() && not(g.MoveNext()) then true else false
let(|I|_|)(n,g)=if fN n && fN g then (let n,g=fUR n,fUR g in if fUC n=fUC g then Some(n,g) else None) else None
let(|G|_|)(n:string,g:string)=try let n,g=(int n,int g) in Some(n,g) with _->None
let(|E|_|)(n:string,g:string)=if n.[0]='0' || g.[0]='0' then match (n,g) with G(e,l)->Some(e,l,max n.Length g.Length) |_->None else None
let fL n=let fN i g e l=let n=[i..(if i>g then -l else l)..g] in if e="-" then List.rev n else n
let fG n g=let n,buf=string n, System.Text.StringBuilder() in (for _ in 1..g-n.Length do buf.Append 0); buf.Append n; buf.ToString()
match System.Text.RegularExpressions.Regex.Match(n,@"^(?<n>.*?){(?<i>.*?)\.\.(?<g>.*?)(\.\.(?<e>[-]+)?(?<l>[0-9]*?))?}(?<s>.*)$") with
Valid(n,i,g,e,l,s)->match (i,g) with I(i,g)->Some(fN i.Value g.Value e l|>Seq.map(fun g->sprintf "%s%A%s" n (System.Text.Rune(g)) s))
|E(i,g,z)->Some(fN i g e l|>Seq.map(fun g->sprintf "%s%s%s" n (fG g z) s))
|G(i,g)->Some(fN i g e l|>Seq.map(fun g->sprintf "%s%A%s" n (string g) s)) |_->None
|_->None
let rec expBraces n=seq{match fL n with Some n->yield!(n|>Seq.collect(expBraces)) |_->yield n}
let tests=["simpleNumberRising{1..3}.txt";"steppedNumberRising{1..6..2}.txt";"reverseSteppedNumberRising{1..6..-2}.txt";"steppedNumberDescending{20..9..2}.txt";"simpleAlphaDescending-{Z..X}.txt";"steppedDownAndPadded-{10..00..5}.txt";"minusSignFlipsSequence {030..20..-5}.txt";"combined-{Q..P}{2..1}.txt";"emoji{🌵..🌶}{🌽..🌾}etc";"li{teral";"rangeless{random}string";"rangeless{}empty";"steppedAlphaDescending-{Z..M..2}.txt";"reversedSteppedAlphaDescending-{Z..M..-2}.txt"]
tests|>List.iter(fun g->printfn $"%s{g}->"; for n in expBraces g do printfn $" %s{n}")
</syntaxhighlight>
{{out}}
<pre>
simpleNumberRising{1..3}.txt->
simpleNumberRising1.txt
simpleNumberRising2.txt
simpleNumberRising3.txt
steppedNumberRising{1..6..2}.txt->
steppedNumberRising1.txt
steppedNumberRising3.txt
steppedNumberRising5.txt
reverseSteppedNumberRising{1..6..-2}.txt->
reverseSteppedNumberRising5.txt
reverseSteppedNumberRising3.txt
reverseSteppedNumberRising1.txt
steppedNumberDescending{20..9..2}.txt->
steppedNumberDescending"20".txt
steppedNumberDescending"18".txt
steppedNumberDescending"16".txt
steppedNumberDescending"14".txt
steppedNumberDescending"12".txt
steppedNumberDescending"10".txt
simpleAlphaDescending-{Z..X}.txt->
simpleAlphaDescending-Z.txt
simpleAlphaDescending-Y.txt
simpleAlphaDescending-X.txt
steppedDownAndPadded-{10..00..5}.txt->
steppedDownAndPadded-10.txt
steppedDownAndPadded-05.txt
steppedDownAndPadded-00.txt
minusSignFlipsSequence {030..20..-5}.txt->
minusSignFlipsSequence 020.txt
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
combined-{Q..P}{2..1}.txt->
combined-Q2.txt
combined-Q1.txt
combined-P2.txt
combined-P1.txt
emoji{🌵..🌶}{🌽..🌾}etc->
emoji🌵🌽etc
emoji🌵🌾etc
emoji🌶🌽etc
emoji🌶🌾etc
li{teral->
li{teral
rangeless{random}string->
rangeless{random}string
rangeless{}empty->
rangeless{}empty
steppedAlphaDescending-{Z..M..2}.txt->
steppedAlphaDescending-Z.txt
steppedAlphaDescending-X.txt
steppedAlphaDescending-V.txt
steppedAlphaDescending-T.txt
steppedAlphaDescending-R.txt
steppedAlphaDescending-P.txt
steppedAlphaDescending-N.txt
reversedSteppedAlphaDescending-{Z..M..-2}.txt->
reversedSteppedAlphaDescending-N.txt
reversedSteppedAlphaDescending-P.txt
reversedSteppedAlphaDescending-R.txt
reversedSteppedAlphaDescending-T.txt
reversedSteppedAlphaDescending-V.txt
reversedSteppedAlphaDescending-X.txt
reversedSteppedAlphaDescending-Z.txt
</pre>
=={{header|Go}}==
{{trans|Wren}}
<
import (
Line 117 ⟶ 474:
"unicode/utf8"
)
func sign(n int) int {
switch {
case n < 0:
return -1
case n > 0:
return 1
}
return 0
}
func abs(n int) int {
if n < 0 {
return -n
}
return n
}
func parseRange(r string) []string {
Line 168 ⟶ 542:
if n3 < 0 {
asc = !asc
d := abs(n1-n2) % (-n3)
n1 = n2 - d*sign(n2-n1)
n2 = t
n3 = -n3
}
Line 233 ⟶ 610:
"steppedDownAndPadded-{10..00..5}.txt",
"minusSignFlipsSequence {030..20..-5}.txt",
"reverseSteppedNumberRising{1..6..-2}.txt",
"combined-{Q..P}{2..1}.txt",
"emoji{🌵..🌶}{🌽..🌾}etc",
Line 241 ⟶ 619:
"steppedAlphaRising{P..Z..2}.txt",
"stops after endpoint-{02..10..3}.txt",
"steppedNumberRising{1..6..2}.txt",
"steppedNumberDescending{20..9..2}",
"steppedAlphaDescending-{Z..M..2}.txt",
"reversedSteppedAlphaDescending-{Z..M..-2}.txt",
}
for _, s := range examples {
Line 248 ⟶ 630:
fmt.Println()
}
}</
{{out}}
Line 254 ⟶ 636:
Same as Wren entry.
</pre>
=={{header|JavaScript}}==
<
//
// braceExpandWithRange :: String -> [String]
Line 269 ⟶ 650:
braceRangeExpansion()
))(s);
return 0 < expansions.length ? (() => {
const [parsed, residue] =
return suffixAdd(
parsed.reduce(
uncurry(suffixMultiply),
[
)
)([residue.join(
})() : [s];
};
//
// braceRangeExpansion :: [String]
Line 298 ⟶ 679:
affixLeaf(),
fmapP(xs => [xs])(
between(char(
altP(
numericSequence()
Line 310 ⟶ 691:
//
// main :: IO ()
const main = () => {
const tests = [
"rangeless{random}string"
];
return tests.map(s => {
expanded = braceExpandWithRange(s
.join("\n\t");
return `${s} -> \n\t${expanded}`;
})
.join("\n\n");
};
//
// affixLeaf :: () -> Parser String
Line 340 ⟶ 725:
// characters before or after a pair of braces.
fmapP(cs => [
[cs.join(
])(
many(choice([noneOf(
);
Line 352 ⟶ 737:
fmapP(ab => {
const [from, to] = ab;
return from !== to ? (
enumFromThenToChar(from)(
Line 359 ⟶ 745:
})(
ordinalRange(satisfy(
c => !
))
);
Line 375 ⟶ 761:
[from, to, by] = triple.map(
sn => (sn[0] ? negate : identity)(
parseInt(sn[1], 10)
)
);
return map(
compose(justifyRight(w)(
)(
)(
enumFromThenTo(from)(
from + (
to < from ? (
-abs(by)
) : abs(by)
)
)(to)
)
);
};
Line 396 ⟶ 791:
// The String component contains the digits.
bindP(
option(
)(sign => bindP(
some(digit())
Line 422 ⟶ 817:
option(Tuple(false)(1))(
bindP(
string(
)(
numericPart()
)(pureP))
Line 438 ⟶ 833:
p
)(from => bindP(
string(
)(
p
)(compose(pureP, append([from])))));
Line 452 ⟶ 847:
(a, x) => (0 < a) || (1 > x.length) ? (
a
) :
0
);
Line 469 ⟶ 864:
//
// Parser :: String -> [(a, String)] -> Parser a
Line 475 ⟶ 870:
// A function lifted into a Parser object.
({
type:
parser: f
});
Line 485 ⟶ 880:
q => Parser(s => {
const xs = parse(p)(s);
return 0 < xs.length ? (
xs
Line 498 ⟶ 894:
p => Parser(
s => parse(pf)(s).flatMap(
fmapP(
)(
)
);
Line 512 ⟶ 908:
pClose => p => bindP(
pOpen
)(
p
)(x => bindP(
pClose
)(
Line 529 ⟶ 925:
f => Parser(
s => parse(p)(s).flatMap(
)
);
Line 537 ⟶ 933:
const char = x =>
// A particular single character.
satisfy(c => x === c);
Line 556 ⟶ 952:
const emptyP = () =>
// The empty list.
Parser(
// escape :: Parser String
const escape = () =>
fmapP(xs => xs.join(
sequenceP([char(
);
Line 572 ⟶ 968:
p => Parser(
s => parse(p)(s).flatMap(
)
);
Line 580 ⟶ 976:
const item = () =>
// A single character.
Parser(s => {
return Boolean(h) ?
Tuple(h)(t)
] : [];
});
Line 602 ⟶ 998:
// Lifts a parser for a simple type of value
// to a parser for a list of such values.
const
liftA2P(
x => xs => [x].concat(xs)
)(
return Parser(
s => parse(
0 < s.length ? (
altP(
) : pureP([])
)(s)
Line 632 ⟶ 1,029:
const parse = p =>
// The result of parsing s with p.
s =>
Line 649 ⟶ 1,043:
// Any character for which the
// given predicate returns true.
Parser(s => {
return Boolean(h) ?
test(h) ? [
Tuple(h)(t)
] : []
) : [];
});
// sequenceP :: [Parser a] -> Parser [a]
Line 680 ⟶ 1,060:
s => ps.reduce(
(a, q) => a.flatMap(
first(xs =>
)
),
Line 694 ⟶ 1,074:
// Lifts a parser for a simple type of value
// to a parser for a list of such values.
const
altP(some(
return Parser(
s => parse(
liftA2P(
x => xs => [x].concat(xs)
)(p)(
)(s)
);
Line 709 ⟶ 1,090:
const string = s =>
// A particular string.
fmapP(cs => cs.join(
sequenceP([...s].map(char))
);
//
// Tuple (,) :: a -> b -> (a, b)
const Tuple = a =>
b => ({
type:
length: 2,
*[Symbol.iterator]() {
for (const k in this) {
if (!isNaN(k)) {
yield this[k];
}
}
}
});
// abs :: Num -> Num
const abs =
// Absolute value of a given number
// without the sign.
x => 0 > x ? (
-x
) : x;
Line 753 ⟶ 1,150:
// concat :: [[a]] -> [a]
// enumFromThenTo :: Int -> Int -> Int -> [Int]
const enumFromThenTo =
// with a step
nxt => n => {
const d = nxt - m;
return Array.from({
length: (Math.floor(
}, (_, i) =>
};
Line 779 ⟶ 1,173:
.map(x => x.codePointAt(0)),
d = i2 - i1;
return Array.from({
length: (Math.floor(iY - i2) / d) + 2
Line 789 ⟶ 1,184:
// A simple function lifted to one which applies
// to a tuple, transforming only its first item.
// flip :: (a -> b -> c) -> b -> a -> c
const flip = op =>
// The binary function op with
// its arguments reversed.
1 < op.length ? (
(a, b) => op(b, a)
) : (x => y => op(y)(x));
// fromEnum :: Enum a => a -> Int
const fromEnum = x =>
typeof x !==
x.constructor === Object ? (
x.value
) : parseInt(Number(x), 10)
) : x.codePointAt(0);
Line 822 ⟶ 1,209:
// The identity function. (`id`, in Haskell)
x;
Line 832 ⟶ 1,214:
const isDigit = c => {
const n = c.codePointAt(0);
return 48 <= n && 57 >= n;
};
Line 843 ⟶ 1,226:
s.padStart(n, c)
) : s;
Line 865 ⟶ 1,239:
const maxBound = x => {
const e = x.enum;
return Boolean(e) ? (
e[e[x.max]]
) : {
} [typeof x];
};
Line 877 ⟶ 1,252:
const minBound = x => {
const e = x.enum;
return Boolean(e) ? (
e[e[0]]
) : {
} [typeof x];
};
Line 895 ⟶ 1,271:
const pred = x => {
const t = typeof x;
return "number" !== t ? (() => {
const [i, mn] = [x, minBound(x)].map(fromEnum);
return i > mn ? (
toEnum(x)(i - 1)
) : Error(
})() : x > Number.MIN_SAFE_INTEGER ? (
x - 1
) : Error(
};
//
const
Line 924 ⟶ 1,292:
const str = x =>
Array.isArray(x) && x.every(
v => (
) ? (
x.join(
) : x.toString();
Line 933 ⟶ 1,301:
const succ = x => {
const t = typeof x;
return "number" !== t ? (
return i < mx ? (
toEnum(x)(1 + i)
) : Error("succ :: enum out of range.");
})()
) : x < Number.MAX_SAFE_INTEGER ? (
1 + x
) : Error(
};
Line 949 ⟶ 1,323:
// allowing the function to make the right mapping
x => ({
} [typeof e])(x);
Line 960 ⟶ 1,334:
// A function over a pair, derived
// from a curried function.
const
xy = Boolean(args.length % 2) ? (
args[0]
) : args;
return f(xy[0])(xy[1]);
};
Line 971 ⟶ 1,345:
// MAIN ---
return main();
})();</
{{Out}}
<pre>simpleNumberRising{1..3}.txt ->
Line 992 ⟶ 1,366:
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
reverseSteppedNumberRising{1..6..-2}.txt ->
reverseSteppedNumberRising5.txt
reverseSteppedNumberRising3.txt
reverseSteppedNumberRising1.txt
combined-{Q..P}{2..1}.txt ->
Line 1,013 ⟶ 1,392:
rangeless{random}string ->
rangeless{random}string</pre>
=={{header|jq}}==
'''Works with jq, the C implementation of jq'''
'''Works with gojq, the Go implementation of jq'''
This implementation relies on "reluctant" regex parsing.
Range expressions of the form {x..y}, where x and y are single
characters, are allowed, even if exactly one of them is a digit.
When expanding an expression with more than one range, the program
as given below produces an ordering
based on expansion of the left-most range first.
A trivial change in two places is sufficient to produce the alternative ordering.
<syntaxhighlight lang="jq">
# Left-pad with 0s
def lpad($len): tostring | ($len - length) as $l | ("0" * $l) + .;
def expand:
# The key to success here is reluctance (".*?")
def cap:
capture("(?<head>^.*?)[{](?<from>[0-9]+|.)[.][.](?<to>[0-9]+|.)"
+ "([.][.](?<sign>-)?(?<increment>[0-9]))?[}](?<tail>.*)$");
def ton: if . == null then . else tonumber end;
# Produce a stream of integers, handling implicit descent.
# $i and $j should be integers.
# If $i and $j are distinct, then expand($i;$j;null;null) will include both,
# otherwise just $i.
def expand($i; $j; $sign; $increment):
(if $increment == null then 1 else $increment end) as $inc
| if $sign == null
then if $i <= $j
then range($i; $j + 1; $inc)
else range($i; $j - 1; - $inc)
end
else [expand($i; $j; null; $increment)] | reverse[]
end ;
# Produce a stream of single characters, handling implicit descent
def explode($x; $y; $sign; $increment):
($x|explode[0]) as $x
| ($y|explode[0]) as $y
| expand($x; $y; $sign; $increment)
| [.] | implode;
# The number of leading 0s of the input string
def leadingZeros: match("^0*") | .string | length;
def padding($x; $y):
($x | leadingZeros) as $a
| ($y | leadingZeros) as $b
| [if $a > 0 then ($x|length) else 0 end,
if $b > 0 then ($y|length) else 0 end]
| max;
( cap as $c
| if ($c.from|test("[0-9]+")) and ($c.to|test("[0-9]+"))
then padding($c.from; $c.to) as $padding
| $c.head
+ ( expand($c.from|tonumber;
$c.to|tonumber;
$c.sign;
$c.increment | ton) | lpad($padding))
+ ($c.tail | expand)
elif ($c.from|length == 1) and ($c.to|length == 1)
then $c.head + explode($c.from; $c.to; $c.sign; $c.increment|ton)
+ ($c.tail | expand)
else ""
end )
// . ;
def examples:
"simpleNumberRising{1..3}.txt",
"simpleAlphaDescending-{Z..X}.txt",
"steppedDownAndPadded-{10..00..5}.txt",
"minusSignFlipsSequence {030..20..-5}.txt",
"reverseSteppedNumberRising{1..6..-2}.txt",
"combined-{Q..P}{2..1}.txt",
"emoji{🌵..🌶}{🌽..🌾}etc",
"li{teral",
"rangeless{}empty",
"rangeless{random}string",
"mixedNumberAlpha{5..k}",
"steppedAlphaRising{P..Z..2}.txt",
"stops after endpoint-{02..10..3}.txt",
"steppedNumberRising{1..6..2}.txt",
"steppedNumberDescending{20..9..2}",
"steppedAlphaDescending-{Z..M..2}.txt",
"reversedSteppedAlphaDescending-{Z..M..-2}.txt"
;
examples
| "\(.) ->",
" \(expand)", ""
</syntaxhighlight>
{{output}}
<pre style="height:20lh;overflow:auto>
simpleNumberRising{1..3}.txt ->
simpleNumberRising1.txt
simpleNumberRising2.txt
simpleNumberRising3.txt
simpleAlphaDescending-{Z..X}.txt ->
simpleAlphaDescending-Z.txt
simpleAlphaDescending-Y.txt
simpleAlphaDescending-X.txt
steppedDownAndPadded-{10..00..5}.txt ->
steppedDownAndPadded-10.txt
steppedDownAndPadded-05.txt
steppedDownAndPadded-00.txt
minusSignFlipsSequence {030..20..-5}.txt ->
minusSignFlipsSequence 020.txt
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
reverseSteppedNumberRising{1..6..-2}.txt ->
reverseSteppedNumberRising5.txt
reverseSteppedNumberRising3.txt
reverseSteppedNumberRising1.txt
combined-{Q..P}{2..1}.txt ->
combined-Q2.txt
combined-P2.txt
combined-Q1.txt
combined-P1.txt
emoji{🌵..🌶}{🌽..🌾}etc ->
emoji🌵🌽etc
emoji🌶🌽etc
emoji🌵🌾etc
emoji🌶🌾etc
li{teral ->
li{teral
rangeless{}empty ->
rangeless{}empty
rangeless{random}string ->
rangeless{random}string
mixedNumberAlpha{5..k} ->
mixedNumberAlpha5
mixedNumberAlpha6
mixedNumberAlpha7
mixedNumberAlpha8
mixedNumberAlpha9
mixedNumberAlpha:
mixedNumberAlpha;
mixedNumberAlpha<
mixedNumberAlpha=
mixedNumberAlpha>
mixedNumberAlpha?
mixedNumberAlpha@
mixedNumberAlphaA
mixedNumberAlphaB
mixedNumberAlphaC
mixedNumberAlphaD
mixedNumberAlphaE
mixedNumberAlphaF
mixedNumberAlphaG
mixedNumberAlphaH
mixedNumberAlphaI
mixedNumberAlphaJ
mixedNumberAlphaK
mixedNumberAlphaL
mixedNumberAlphaM
mixedNumberAlphaN
mixedNumberAlphaO
mixedNumberAlphaP
mixedNumberAlphaQ
mixedNumberAlphaR
mixedNumberAlphaS
mixedNumberAlphaT
mixedNumberAlphaU
mixedNumberAlphaV
mixedNumberAlphaW
mixedNumberAlphaX
mixedNumberAlphaY
mixedNumberAlphaZ
mixedNumberAlpha[
mixedNumberAlpha\
mixedNumberAlpha]
mixedNumberAlpha^
mixedNumberAlpha_
mixedNumberAlpha`
mixedNumberAlphaa
mixedNumberAlphab
mixedNumberAlphac
mixedNumberAlphad
mixedNumberAlphae
mixedNumberAlphaf
mixedNumberAlphag
mixedNumberAlphah
mixedNumberAlphai
mixedNumberAlphaj
mixedNumberAlphak
steppedAlphaRising{P..Z..2}.txt ->
steppedAlphaRisingP.txt
steppedAlphaRisingR.txt
steppedAlphaRisingT.txt
steppedAlphaRisingV.txt
steppedAlphaRisingX.txt
steppedAlphaRisingZ.txt
stops after endpoint-{02..10..3}.txt ->
stops after endpoint-02.txt
stops after endpoint-05.txt
stops after endpoint-08.txt
steppedNumberRising{1..6..2}.txt ->
steppedNumberRising1.txt
steppedNumberRising3.txt
steppedNumberRising5.txt
steppedNumberDescending{20..9..2} ->
steppedNumberDescending20
steppedNumberDescending18
steppedNumberDescending16
steppedNumberDescending14
steppedNumberDescending12
steppedNumberDescending10
steppedAlphaDescending-{Z..M..2}.txt ->
steppedAlphaDescending-Z.txt
steppedAlphaDescending-X.txt
steppedAlphaDescending-V.txt
steppedAlphaDescending-T.txt
steppedAlphaDescending-R.txt
steppedAlphaDescending-P.txt
steppedAlphaDescending-N.txt
reversedSteppedAlphaDescending-{Z..M..-2}.txt ->
reversedSteppedAlphaDescending-N.txt
reversedSteppedAlphaDescending-P.txt
reversedSteppedAlphaDescending-R.txt
reversedSteppedAlphaDescending-T.txt
reversedSteppedAlphaDescending-V.txt
reversedSteppedAlphaDescending-X.txt
reversedSteppedAlphaDescending-Z.txt
</pre>
=={{header|Julia}}==
<
function ranged(str)
Line 1,056 ⟶ 1,681:
println(test, "->\n", [" " * x * "\n" for x in splatrange(test)]...)
end
</
<pre>
simpleNumberRising{1..3}.txt->
Line 1,116 ⟶ 1,741:
</pre>
=={{header|
{{trans|Wren}}
<syntaxhighlight lang="nim">import options, strutils, unicode
func intFromString(s: string): Option[int] =
## Try to parse an int. Return some(int) if parsing
## was successful, return none(int) if it failed.
try:
let
result
except ValueError:
func parseRange(r: string): seq[string] =
if r.len == 0: return @["{}"] # rangeless, empty.
let sp = r.split("..")
if sp.len == 1: return @['{' & r & '}']
let first = sp[0]
let last = sp[1]
let incr = if sp.len == 2: "1" else: sp[2]
let val1 = intFromString(first)
let val2 = intFromString(last)
let val3 = intFromString(incr)
if val3.isNone(): return @['{' & r & '}'] # increment isn't a number.
var n3 = val3.get()
let numeric = val1.isSome and val2.isSome
var n1, n2: int
if numeric:
n1 = val1.get()
n2 = val2.get()
else:
if val1.isSome and val2.isNone or val1.isNone and val2.isSome:
return @['{' & r & '}'] # mixed numeric/alpha not expanded.
if first.runeLen != 1 or last.runeLen != 1:
return @['{' & r & '}'] # start/end are not both single
n1 = first.toRunes[0].int
n2 = last.toRunes[0].int
var width = 1
if numeric:
width = if first.len < last.len: last.len else: first.len
if n3 == 0:
# Zero increment.
return if numeric: @[n1.intToStr(width)] else: @[first]
var asc = n1 < n2
if n3 < 0:
asc = not asc
swap n1, n2
n3 = -n3
var i = n1
if asc:
result.add if numeric: i.intToStr(width) else: $Rune(i)
inc i, n3
else:
result.add if numeric: i.intToStr(width) else: $Rune(i)
func rangeExpand(s: string): seq[string] =
var rng = ""
var inRng = false
for c in s:
if c == '{' and not inRng:
inRng = true
rng = ""
elif c == '}' and
let rngRes =
var res:
for i
for j in
result
inRng
elif
rng.add
for s in result.mitems: s.add c
if inRng:
for s in result.mitems: s.add '{' & rng # unmatched braces.
when isMainModule:
const Examples = ["simpleNumberRising{1..3}.txt",
"
"
"
"
"li{teral",
"rangeless{}empty",
"rangeless{random}string",
"mixedNumberAlpha{5..k}",
"steppedAlphaRising{P..Z..2}.txt",
"stops after endpoint-{02..10..3}.txt"]
for s in Examples:
stdout.write s, " →\n "
let res = rangeExpand(s)
stdout.write res.join("\n ")
echo '\n'
</syntaxhighlight>
{{out}}
<pre>simpleNumberRising{1..3}.txt →
simpleNumberRising1.txt
simpleNumberRising2.txt
simpleNumberRising3.txt
simpleAlphaDescending-{Z..X}.txt →
simpleAlphaDescending-Z.txt
simpleAlphaDescending-Y.txt
simpleAlphaDescending-X.txt
steppedDownAndPadded-{10..00..5}.txt →
steppedDownAndPadded-10.txt
steppedDownAndPadded-05.txt
steppedDownAndPadded-00.txt
minusSignFlipsSequence {030..20..-5}.txt →
minusSignFlipsSequence 020.txt
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
combined-{Q..P}{2..1}.txt →
combined-Q2.txt
combined-Q1.txt
combined-P2.txt
combined-P1.txt
emoji{🌵..🌶}{🌽..🌾}etc →
emoji🌵🌽etc
emoji🌵🌾etc
emoji🌶🌽etc
emoji🌶🌾etc
li{teral →
li{teral
rangeless{}empty →
rangeless{}empty
rangeless{random}string →
rangeless{random}string
mixedNumberAlpha{5..k} →
mixedNumberAlpha{5..k}
steppedAlphaRising{P..Z..2}.txt →
steppedAlphaRisingP.txt
steppedAlphaRisingR.txt
steppedAlphaRisingT.txt
steppedAlphaRisingV.txt
steppedAlphaRisingX.txt
steppedAlphaRisingZ.txt
stops after endpoint-{02..10..3}.txt →
stops after endpoint-02.txt
stops after endpoint-05.txt
stops after endpoint-08.txt
</pre>
=={{header|Phix}}==
{{trans|Wren}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"0.8.2"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (is_integer() is new, plus "==sign(inc)" found me a long-buried compiler bug)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">parse_range</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">sp</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">,</span><span style="color: #008000;">".."</span><span style="color: #0000FF;">)&{</span><span style="color: #008000;">"1"</span><span style="color: #0000FF;">},</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sp</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">3</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">,</span><span style="color: #000000;">step</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sp</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">inc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">step</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">inc</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">ns</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">is_integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">ne</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">is_integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ns</span><span style="color: #0000FF;">=</span><span style="color: #000000;">ne</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ns</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">w</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">inc</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">,</span><span style="color: #000000;">inc</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">e</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">inc</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">></span><span style="color: #000000;">e</span> <span style="color: #008080;">then</span> <span style="color: #000000;">inc</span> <span style="color: #0000FF;">*=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">zfill</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">)></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">strange</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">or</span>
<span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">)></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ending</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">zfill</span><span style="color: #0000FF;">?</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%%0%dd"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">w</span><span style="color: #0000FF;">}):</span><span style="color: #008000;">"%d"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">s</span> <span style="color: #008080;">to</span> <span style="color: #000000;">e</span> <span style="color: #008080;">by</span> <span style="color: #000000;">inc</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: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">))</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;">elsif</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">)=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">ok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">ok</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">s32</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">utf8_to_utf32</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">e32</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">utf8_to_utf32</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s32</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s32</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span>
<span style="color: #008080;">and</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">e32</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">e32</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">ok</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ok</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">strange</span><span style="color: #0000FF;">></span><span style="color: #000000;">ending</span> <span style="color: #008080;">then</span> <span style="color: #000000;">inc</span> <span style="color: #0000FF;">*=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</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;">strange</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">sdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">strange</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">inc</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">#FF</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">#00</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">strange</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ch</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">strange</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">inc</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">#FF</span><span style="color: #0000FF;">:</span><span style="color: #000000;">#00</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">strange</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ending</span><span style="color: #0000FF;">)==</span><span style="color: #7060A8;">sign</span><span style="color: #0000FF;">(</span><span style="color: #000000;">inc</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)></span><span style="color: #000000;">10</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (sanity check)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- ([utf8] strings not single char)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (neither numeric nor same-length alpha)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (mixed numeric/alpha)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (non-numeric increment)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (rangeless)</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"{"</span><span style="color: #0000FF;">&</span><span style="color: #000000;">r</span><span style="color: #0000FF;">&</span><span style="color: #008000;">"}"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">range_expand</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">""</span><span style="color: #0000FF;">}</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">range</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">in_range</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">k</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;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">==</span> <span style="color: #008000;">'{'</span> <span style="color: #008080;">and</span> <span style="color: #008080;">not</span> <span style="color: #000000;">in_range</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">in_range</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #000000;">range</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">==</span> <span style="color: #008000;">'}'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">in_range</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">range_res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_range</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">prev_res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">res</span>
<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;">prev_res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</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;">range_res</span><span style="color: #0000FF;">)</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;">prev_res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">range_res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</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;">for</span>
<span style="color: #000000;">in_range</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">in_range</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">range</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">c</span>
<span style="color: #008080;">else</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;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">c</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;">if</span> <span style="color: #000000;">in_range</span> <span style="color: #008080;">then</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;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">"{"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">range</span> <span style="color: #000080;font-style:italic;">// unmatched braces</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;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">examples</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span>
<span style="color: #008000;">"simpleNumberRising{1..3}.txt"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"simpleAlphaDescending-{Z..X}.txt"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"steppedDownAndPadded-{10..00..5}.txt"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"minusSignFlipsSequence {030..20..-5}.txt"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"combined-{Q..P}{2..1}.txt"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"emoji{🌵..🌶}{🌽..🌾}etc"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"multi char emoji ranges fail {🌵🌵..🌵🌶}"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"li{teral"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"rangeless{}empty"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"rangeless{random}string"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"mixedNumberAlpha{5..k}"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"steppedAlphaRising{P..Z..2}.txt"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"stops after endpoint-{02..10..3}.txt"</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;">examples</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">examples</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s ->\n %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range_expand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">),</span><span style="color: #008000;">"\n "</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
Note that, as usual, unicode output does not look good on a windows console for tests 6 & 7 (linux output shown)
Line 1,285 ⟶ 2,088:
stops after endpoint-08.txt
</pre>
=={{header|Python}}==
<syntaxhighlight lang="python">"""Brace expansion using ranges. Requires Python >= 3.6.
Here we use regular expressions for parsing and take an object orientated approach
to expansion of range expressions.
This implementation supports stepped ordinal range expressions.
"""
Line 1,417 ⟶ 2,213:
# A negative step means we reverse the range.
start, stop = stop, start
if start < stop:
step = abs(step)
else:
start -= 1
stop -= 1
elif start > stop:
Line 1,463 ⟶ 2,264:
cases = [
r"simpleNumberRising{1..3}.txt",
r"simpleAlphaDescending-{Z..X}.txt",
r"steppedDownAndPadded-{10..00..5}.txt",
r"minusSignFlipsSequence {030..20..-5}.txt",
r"reverseSteppedNumberRising{1..6..-2}.txt",
r"combined-{Q..P}{2..1}.txt",
r"emoji{🌵..🌶}{🌽..🌾}etc",
r"li{teral",
r"rangeless{}empty",
r"rangeless{random}string",
# Extra examples, not from the task description.
r"steppedNumberRising{1..6..2}.txt",
r"steppedNumberDescending{20..9..2}.txt",
r"steppedAlphaDescending-{Z..M..2}.txt",
r"reverseSteppedAlphaRising{A..F..-2}.txt",
r"reversedSteppedAlphaDescending-{Z..M..-2}.txt",
]
Line 1,489 ⟶ 2,293:
if __name__ == "__main__":
examples()
</syntaxhighlight>
{{out}}
Line 1,497 ⟶ 2,301:
simpleNumberRising2.txt
simpleNumberRising3.txt
simpleAlphaDescending-{Z..X}.txt ->
Line 1,525 ⟶ 2,316:
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
reverseSteppedNumberRising{1..6..-2}.txt ->
reverseSteppedNumberRising5.txt
reverseSteppedNumberRising3.txt
reverseSteppedNumberRising1.txt
combined-{Q..P}{2..1}.txt ->
Line 1,540 ⟶ 2,336:
li{teral ->
li{teral
rangeless{}empty ->
rangeless{}empty
rangeless{random}string ->
rangeless{random}string
steppedNumberRising{1..6..2}.txt ->
steppedNumberRising1.txt
steppedNumberRising3.txt
steppedNumberRising5.txt
steppedNumberDescending{20..9..2}.txt ->
steppedNumberDescending20.txt
steppedNumberDescending18.txt
steppedNumberDescending16.txt
steppedNumberDescending14.txt
steppedNumberDescending12.txt
steppedNumberDescending10.txt
steppedAlphaDescending-{Z..M..2}.txt ->
Line 1,555 ⟶ 2,364:
steppedAlphaDescending-P.txt
steppedAlphaDescending-N.txt
reverseSteppedAlphaRising{A..F..-2}.txt ->
reverseSteppedAlphaRisingE.txt
reverseSteppedAlphaRisingC.txt
reverseSteppedAlphaRisingA.txt
reversedSteppedAlphaDescending-{Z..M..-2}.txt ->
Line 1,565 ⟶ 2,379:
reversedSteppedAlphaDescending-Y.txt
</pre>
=={{header|Raku}}==
{{works with|Rakudo|2020.08.1}}
Also implements some of the string list functions described on the bash-hackers page.
<syntaxhighlight lang="raku"
my $list = rx/ ^ $<prefix> = .*? '{' (<-[,}]>+) +%% ',' '}' $<postfix> = .* $/;
Line 1,657 ⟶ 2,470:
say '';
}
</syntaxhighlight>
{{out}}
<pre>simpleNumberRising{1..3}.txt ->
Line 1,748 ⟶ 2,561:
multi char emoji ranges fail {🌵🌵..🌵🌶}
</pre>
=={{header|Wren}}==
{{libheader|Wren-fmt}}
Added
<syntaxhighlight lang="wren">import "./fmt" for Fmt
var parseRange = Fn.new { |r|
Line 1,784 ⟶ 2,592:
asc = !asc
var t = n1
n1 = n2 - d * (n2 - n1).sign
n2 = t
n3 = -n3
Line 1,835 ⟶ 2,644:
"steppedDownAndPadded-{10..00..5}.txt",
"minusSignFlipsSequence {030..20..-5}.txt",
"reverseSteppedNumberRising{1..6..-2}.txt",
"combined-{Q..P}{2..1}.txt",
"emoji{🌵..🌶}{🌽..🌾}etc",
Line 1,842 ⟶ 2,652:
"mixedNumberAlpha{5..k}",
"steppedAlphaRising{P..Z..2}.txt",
"stops after endpoint-{02..10..3}.txt",
"steppedNumberRising{1..6..2}.txt",
"steppedNumberDescending{20..9..2}",
"steppedAlphaDescending-{Z..M..2}.txt",
"reversedSteppedAlphaDescending-{Z..M..-2}.txt"
]
Line 1,850 ⟶ 2,664:
System.print(res.join("\n "))
System.print()
}</
{{out}}
Line 1,873 ⟶ 2,687:
minusSignFlipsSequence 025.txt
minusSignFlipsSequence 030.txt
reverseSteppedNumberRising{1..6..-2}.txt ->
reverseSteppedNumberRising5.txt
reverseSteppedNumberRising3.txt
reverseSteppedNumberRising1.txt
combined-{Q..P}{2..1}.txt ->
Line 1,910 ⟶ 2,729:
stops after endpoint-05.txt
stops after endpoint-08.txt
steppedNumberRising{1..6..2}.txt ->
steppedNumberRising1.txt
steppedNumberRising3.txt
steppedNumberRising5.txt
steppedNumberDescending{20..9..2} ->
steppedNumberDescending20
steppedNumberDescending18
steppedNumberDescending16
steppedNumberDescending14
steppedNumberDescending12
steppedNumberDescending10
steppedAlphaDescending-{Z..M..2}.txt ->
steppedAlphaDescending-Z.txt
steppedAlphaDescending-X.txt
steppedAlphaDescending-V.txt
steppedAlphaDescending-T.txt
steppedAlphaDescending-R.txt
steppedAlphaDescending-P.txt
steppedAlphaDescending-N.txt
reversedSteppedAlphaDescending-{Z..M..-2}.txt ->
reversedSteppedAlphaDescending-N.txt
reversedSteppedAlphaDescending-P.txt
reversedSteppedAlphaDescending-R.txt
reversedSteppedAlphaDescending-T.txt
reversedSteppedAlphaDescending-V.txt
reversedSteppedAlphaDescending-X.txt
reversedSteppedAlphaDescending-Z.txt
</pre>
|