Brace expansion: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
(→‎{{header|jq}}: conform to lexicographic ordering requirement)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(7 intermediate revisions by 3 users not shown)
Line 2,466:
| if ($depth > 0) and (.c == "," or .c == "}")
then .return = [.out, .s]
else .cont = false
| if .c == "{"
then (.s[1:] | getGroup($depth+1)) as $x
| if $x[0] | length > 0
# conform to the "lexicographic" ordering requirement
then .out |= [ .[] as $o | $o + $x[0][] ]
| .s = $x[1]
| .cont = true
else .
end
else .
end
end
| if (.cont | not)
then if (.c == "\\") and ((.s|length) > 1)
then .c += .s[1:2]
| .s |= .[1:]
else .
end
| .out = [.out[] + .c]
| .s |= .[1:]
else .
end )
| if .return then .return else [.out, .s] end ;
 
getItem(0)[0];
Line 4,989:
 
templates collateSequence
data part <[]|''> local
@: [''];
$... -> #
$@!
when <´part´ '.*'> do
def part: $;
@: [$@... -> '$;$part;'];
Line 5,039 ⟶ 5,040:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
 
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
Line 5,145 ⟶ 5,147:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|TXR}}==
 
The approach here is to parse the notation into a nested tree of strings. In the following diagram the <code>-></code> arrow indicates that the tree on the left denotes the list of output strings on the right.
 
A list with no operator symbol denotes catenation:
 
<pre>("foo" "bar") -> ("foobar")</pre>
 
The <code>/</code> symbol (slash, usually denoting arithmetic division) denotes alternation:
 
<pre>(/ "foo" "bar") -> ("foo" "bar")
("inter" (/ "pol" "pret") "ation") -> ("interpolation" "interpretation")</pre>
 
This notation is processed by the <code>bexp-expand</code> function to produce the list of strings which it denotes. The <code>bexp-parse</code> function parses a string containing brace expansion into the above notation.
 
The backslashes and edge cases are handled between the tokenizing and parsing. Backslashed characters are represented as tokens which include the backslash. Thus the <code>\{</code> token compares unequal to <code>{</code> and isn't mistaken for it. These backslashed tokens just look like any other text that has no special meaning.
 
The empty <code>{}</code> is handled as a token, but other cases of braces containing no commas are handled in the parser.
 
When the parser has scanned a complete, valid brace that contains no comma, instead of generating a <code>(/ ...)</code> tree node from the content, it generates <code>("{" ... "}")</code>, rendering the braces as literal strings. The <code>...</code> content may contain <code>/</code> operators, as required.
 
When the parser has scanned an incomplete brace, it puts out <code>("{" ...)</code>: the dangling brace is represented literally, followed by the items that have been parsed out. The comma elements are preserved in this case; the lack of a closing brace turns off their meaning.
 
In the main case of a balanced brace with commas, the parsed out elements are split on the commas, which are removed, and that forms the arguments of <code>/</code> node.
 
<syntaxhighlight lang="txrlisp">;; API
(defun brace-expand (str)
(bexp-expand (bexp-parse str)))
 
;; parser
(defstruct bexp-parse-ctx ()
str
toks)
 
(defun bexp-parse (str)
(let ((ctx (new bexp-parse-ctx
str str
;; tokenizer
toks (remqual "" (tok #/([{},]|{}|\\\\|\\.)/ t str)))))
(build
(whilet ((next (pop ctx.toks)))
(add
(if (equal next "{")
(bexp-parse-brace ctx)
next))))))
 
(defun bexp-parse-brace (ctx)
(buildn
(let ((orig-toks ctx.toks))
(caseq (whilet ((next (pop ctx.toks)))
(casequal next
("{" (add (bexp-parse-brace ctx)))
("}" (return :ok))
(t (add next))))
(:ok
(cond
((memqual "," (get))
(flow (get)
(split* @1 (op where (op equal ",")))
(cons '/)))
(t
(add* "{")
(add "}")
(get))))
(nil
(add* "{")
(get))))))
 
;; expander
(defun bexp-expand (tree : (path (new list-builder)))
(build
(match-case tree
(() (add (cat-str path.(get))))
(((/ . @alt) . @rest)
(let ((saved-path path.(get)))
(each ((elem alt))
path.(oust saved-path)
(pend (bexp-expand (cons elem rest) path)))))
((@(consp @succ) . @rest)
(pend (bexp-expand (append succ rest) path)))
((@head . @rest)
path.(add head)
(pend (bexp-expand rest path))))))
 
;; Tests
(tprint (brace-expand "~/{Downloads,Pictures}/*.{jpg,gif,png}"))
(tprint (brace-expand "It{{em,alic}iz,erat}e{d,}, please."))
(tprint (brace-expand "{,{,gotta have{ ,\\, again\\, }}more }cowbell!"))
(tprint (brace-expand "{}} some }{,{\\\\{ edge, edge} \\,}{ cases, {here} \\\\\\\\\\}"))</syntaxhighlight>
 
{{out}}
 
<pre>~/Downloads/*.jpg
~/Downloads/*.gif
~/Downloads/*.png
~/Pictures/*.jpg
~/Pictures/*.gif
~/Pictures/*.png
Itemized, please.
Itemize, please.
Italicized, please.
Italicize, please.
Iterated, please.
Iterate, please.
cowbell!
more cowbell!
gotta have more cowbell!
gotta have\, again\, more cowbell!
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
 
=={{header|Visual Basic .NET}}==
{{trans|Python}}
Line 5,245 ⟶ 5,359:
{}} some }{,{\ edge \}{ cases, {here} \\\
{}} some }{,{\ edge \}{ cases, {here} \\\</pre>
 
=={{header|Wren}}==
{{trans|Python}}
<syntaxhighlight lang="ecmascriptwren">var getGroup // forward declaration
 
var getItem = Fn.new { |s, depth|
Line 5,342 ⟶ 5,457:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
 
=={{header|zkl}}==
This is a two pass algorithm (2*length(string)), one pass to find valid {} pairs, the next pass to expand them.
9,476

edits