Brace expansion using ranges: Difference between revisions

→‎{{header|jq}}: right-most-first
(→‎{{header|Go}}: Updated in line with Wren example.)
(→‎{{header|jq}}: right-most-first)
 
(5 intermediate revisions by 4 users not shown)
Line 1:
{{draft task}}{{clarified-review}}
 
;Task
{{task heading}}
 
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 111:
* &nbsp; [[Range_expansion|range expansion]]
<br><br>
 
=={{header|11l}}==
{{trans|Nim}}
 
<langsyntaxhighlight lang="11l">F intFromString(s) -> Int?
X.try
R Int(s)
Line 219 ⟶ 218:
V res = rangeExpand(s)
print(res.join("\n "))
print()</langsyntaxhighlight>
 
{{out}}
Line 275 ⟶ 274:
 
</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#}}==
<langsyntaxhighlight 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))
Line 296 ⟶ 397:
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>
</lang>
{{out}}
<pre>
Line 365 ⟶ 466:
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 529 ⟶ 630:
fmt.Println()
}
}</langsyntaxhighlight>
 
{{out}}
Line 535 ⟶ 636:
Same as Wren entry.
</pre>
 
=={{header|JavaScript}}==
<langsyntaxhighlight lang="javascript">(() => {
"use strict";
 
Line 1,245 ⟶ 1,345:
// MAIN ---
return main();
})();</langsyntaxhighlight>
{{Out}}
<pre>simpleNumberRising{1..3}.txt ->
Line 1,292 ⟶ 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}}==
<langsyntaxhighlight lang="julia">padzeros(str) = (len = length(str)) > 1 && str[1] == '0' ? len : 0
 
function ranged(str)
Line 1,335 ⟶ 1,681:
println(test, "->\n", [" " * x * "\n" for x in splatrange(test)]...)
end
</langsyntaxhighlight>{{out}}
<pre>
simpleNumberRising{1..3}.txt->
Line 1,397 ⟶ 1,743:
=={{header|Nim}}==
{{trans|Wren}}
<langsyntaxhighlight Nimlang="nim">import options, strutils, unicode
 
 
Line 1,511 ⟶ 1,857:
stdout.write res.join("\n ")
echo '\n'
</syntaxhighlight>
</lang>
 
{{out}}
Line 1,571 ⟶ 1,917:
stops after endpoint-08.txt
</pre>
 
=={{header|Phix}}==
{{trans|Wren}}
<!--<langsyntaxhighlight Phixlang="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>
Line 1,691 ⟶ 2,036:
<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 -&gt;\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>
<!--</langsyntaxhighlight>-->
{{out}}
Note that, as usual, unicode output does not look good on a windows console for tests 6 & 7 (linux output shown)
Line 1,743 ⟶ 2,088:
stops after endpoint-08.txt
</pre>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">"""Brace expansion using ranges. Requires Python >= 3.6.
 
Here we use regular expressions for parsing and take an object orientated approach
Line 1,949 ⟶ 2,293:
if __name__ == "__main__":
examples()
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,035 ⟶ 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" perl6line>my $range = rx/ '{' $<start> = <-[.]>+? '..' $<end> = <-[.]>+? ['..' $<incr> = ['-'?\d+] ]? '}' /;
my $list = rx/ ^ $<prefix> = .*? '{' (<-[,}]>+) +%% ',' '}' $<postfix> = .* $/;
 
Line 2,127 ⟶ 2,470:
say '';
}
</syntaxhighlight>
</lang>
{{out}}
<pre>simpleNumberRising{1..3}.txt ->
Line 2,218 ⟶ 2,561:
multi char emoji ranges fail {🌵🌵..🌵🌶}
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-fmt}}
Added a few more examples to the minimum number needed for the task.
<langsyntaxhighlight ecmascriptlang="wren">import "./fmt" for Fmt
 
var parseRange = Fn.new { |r|
Line 2,322 ⟶ 2,664:
System.print(res.join("\n "))
System.print()
}</langsyntaxhighlight>
 
{{out}}
2,442

edits