Brace expansion: Difference between revisions
m
→{{header|Wren}}: Changed to Wren S/H
m (→{{header|Wren}}: Changed to Wren S/H) |
|||
(24 intermediate revisions by 14 users not shown) | |||
Line 3:
Brace expansion is a type of parameter expansion [[wp:Bash_%28Unix_shell%29#Brace_expansion|made popular by Unix shells]], where it allows users to specify multiple similar string parameters without having to type them all out. E.g. the parameter <code>enable_{audio,video}</code> would be interpreted as if both <code>enable_audio</code> and <code>enable_video</code> had been specified.
;Task
Write a function that can perform brace expansion on any input string, according to the following specification.<br>
Line 226 ⟶ 227:
{{task heading|Test Cases}}
:::{| class="wikitable" style="white-space: nowrap;"
|-
! Input<br><small style="font-weight:normal">''(single string)''</small>
Line 267 ⟶ 268:
<hr style="clear:both; margin-bottom:1em;"/>
{{Template:Strings}}
:* [[Brace_expansion_using_ranges]]
<br><br>
=={{header|11l}}==
{{trans|Python}}
<
V out = [‘’]
L s != ‘’
Line 311 ⟶ 312:
R ([‘’] * 0, ‘’)
L(s) |‘~/{Downloads,Pictures}/*.{jpg,gif,png}
It{{em,alic}iz,erat}e{d,}, please.
{,{,gotta have{ ,\, again\, }}more }cowbell!
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}’.split("\n")
print(([s] [+] getitem(s)[0]).join("\n\t")"\n")</
{{out}}
<pre>
Line 330 ⟶ 331:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|AppleScript}}==
This may seem like a cheat, but it ''is'' a legitimate and obvious way to tackle the problem with AppleScript in the unlikely event that the need should arise. It adjusts the escape levels in the input text, feeds it as a shell script to macOS's sh shell, and lets ''it'' handle the expansion.
<
use framework "Foundation"
use scripting additions
Line 370:
set AppleScript's text item delimiters to astid
log output -- To see the result without the backslash-escaping.</
{{output}}
Line 391:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}*)</pre>
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">;This one is a lot more simpler than the rest
BraceExp(string, del:="`n") {
Loop, Parse, string
if (A_LoopField = "{")
break
else
substring .= A_LoopField
substr := SubStr(string, InStr(string, "{")+1, InStr(string, "}")-InStr(string, "{")-1)
Loop, Parse, substr, `,
toreturn .= substring . A_LoopField . del
return toreturn
}
Msgbox, % BraceExp("enable_{video,audio}")
Msgbox, % BraceExp("apple {bush,tree}")
Msgbox, % BraceExp("h{i,ello}")
Msgbox, % BraceExp("rosetta{code,stone}")</syntaxhighlight>
{{out}}
<pre>
enable_audio
apple bush
apple tree
hi
hello
rosettacode
rosettastone</pre>
=={{header|C}}==
Handles only properly formed input.
<
#include <stdio.h>
#include <stdlib.h>
Line 763 ⟶ 734:
return 0;
}</
{{out}}
<pre>Pattern: ~/{Downloads,Pictures}/*.{jpg,gif,png}
Line 786 ⟶ 757:
gotta have more cowbell!
gotta have\, again\, more cowbell!</pre>
=={{header|C sharp|C#}}==
This approach turns the string into a tree structure, with Tokens that are either text, a concatenation or an alteration.
{{works with|C sharp|8}}
<
using System.Collections;
using System.Collections.Generic;
Line 1,123 ⟶ 916:
return result;
}
}</
{{trans|Python}}
<
{
const char L = '{', R = '}', S = ',';
Line 1,174 ⟶ 967:
return (null, "");
}
}</
{{out}}
<pre>
Line 1,198 ⟶ 991:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}</pre>
=={{header|C++}}==
C++11 solution:
<syntaxhighlight lang="cpp">#include <iostream>
#include <iterator>
#include <string>
#include <utility>
#include <vector>
namespace detail {
template <typename ForwardIterator>
class tokenizer
{
ForwardIterator _tbegin, _tend, _end;
public:
tokenizer(ForwardIterator begin, ForwardIterator end)
: _tbegin(begin), _tend(begin), _end(end)
{ }
template <typename Lambda>
bool next(Lambda istoken)
{
if (_tbegin == _end) {
return false;
}
_tbegin = _tend;
for (; _tend != _end && !istoken(*_tend); ++_tend) {
if (*_tend == '\\' && std::next(_tend) != _end) {
++_tend;
}
}
if (_tend == _tbegin) {
_tend++;
}
return _tbegin != _end;
}
ForwardIterator begin() const { return _tbegin; }
ForwardIterator end() const { return _tend; }
bool operator==(char c) { return *_tbegin == c; }
};
template <typename List>
void append_all(List & lista, const List & listb)
{
if (listb.size() == 1) {
for (auto & a : lista) {
a += listb.back();
}
} else {
List tmp;
for (auto & a : lista) {
for (auto & b : listb) {
tmp.push_back(a + b);
}
}
lista = std::move(tmp);
}
}
template <typename String, typename List, typename Tokenizer>
List expand(Tokenizer & token)
{
std::vector<List> alts{ { String() } };
while (token.next([](char c) { return c == '{' || c == ',' || c == '}'; })) {
if (token == '{') {
append_all(alts.back(), expand<String, List>(token));
} else if (token == ',') {
alts.push_back({ String() });
} else if (token == '}') {
if (alts.size() == 1) {
for (auto & a : alts.back()) {
a = '{' + a + '}';
}
return alts.back();
} else {
for (std::size_t i = 1; i < alts.size(); i++) {
alts.front().insert(alts.front().end(),
std::make_move_iterator(std::begin(alts[i])),
std::make_move_iterator(std::end(alts[i])));
}
return std::move(alts.front());
}
} else {
for (auto & a : alts.back()) {
a.append(token.begin(), token.end());
}
}
}
List result{ String{ '{' } };
append_all(result, alts.front());
for (std::size_t i = 1; i < alts.size(); i++) {
for (auto & a : result) {
a += ',';
}
append_all(result, alts[i]);
}
return result;
}
} // namespace detail
template <
typename ForwardIterator,
typename String = std::basic_string<
typename std::iterator_traits<ForwardIterator>::value_type
>,
typename List = std::vector<String>
>
List expand(ForwardIterator begin, ForwardIterator end)
{
detail::tokenizer<ForwardIterator> token(begin, end);
List list{ String() };
while (token.next([](char c) { return c == '{'; })) {
if (token == '{') {
detail::append_all(list, detail::expand<String, List>(token));
} else {
for (auto & a : list) {
a.append(token.begin(), token.end());
}
}
}
return list;
}
template <
typename Range,
typename String = std::basic_string<typename Range::value_type>,
typename List = std::vector<String>
>
List expand(const Range & range)
{
using Iterator = typename Range::const_iterator;
return expand<Iterator, String, List>(std::begin(range), std::end(range));
}
int main()
{
for (std::string string : {
R"(~/{Downloads,Pictures}/*.{jpg,gif,png})",
R"(It{{em,alic}iz,erat}e{d,}, please.)",
R"({,{,gotta have{ ,\, again\, }}more }cowbell!)",
R"({}} some {\\{edge,edgy} }{ cases, here\\\})",
R"(a{b{1,2}c)",
R"(a{1,2}b}c)",
R"(a{1,{2},3}b)",
R"(a{b{1,2}c{}})",
R"(more{ darn{ cowbell,},})",
R"(ab{c,d\,e{f,g\h},i\,j{k,l\,m}n,o\,p}qr)",
R"({a,{\,b}c)",
R"(a{b,{{c}})",
R"({a{\}b,c}d)",
R"({a,b{{1,2}e}f)",
R"({}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\})",
R"({{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{)",
}) {
std::cout << string << '\n';
for (auto expansion : expand(string)) {
std::cout << " " << expansion << '\n';
}
std::cout << '\n';
}
return 0;
}</syntaxhighlight>
=={{header|Common Lisp}}==
<
(alternatives nil :type list))
Line 1,285 ⟶ 1,253:
(dolist (output (expand input))
(format t " ~A~%" output))
(terpri)))</
{{out}}
<pre>~/{Downloads,Pictures}/*.{jpg,gif,png}
Line 1,313 ⟶ 1,281:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|D}}==
{{trans|Python}}
This code is not UTF-corrected, because it uses slicing instead of front, popFront, etc.
<
Nullable!(Tuple!(string[], string)) getGroup(string s, in uint depth)
Line 1,397 ⟶ 1,364:
foreach (const s; testCases.splitLines)
writefln("%s\n%-( %s\n%)\n", s, s.getItems[0]);
}</
{{out}}
<pre>~/{Downloads,Pictures}/*.{jpg,gif,png}
Line 1,469 ⟶ 1,436:
{a,b{2e}f
</pre>
=={{header|Elixir}}==
{{trans|Ruby}}
<
def getitem(s), do: getitem(String.codepoints(s), 0, [""])
Line 1,523 ⟶ 1,489:
|> Enum.each(fn str -> IO.puts "\t#{str}" end)
IO.puts ""
end)</
{{out}}
Line 1,553 ⟶ 1,519:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Go}}==
<code>expand.go</code>:
<
// Expander is anything that can be expanded into a slice of strings.
Line 1,757 ⟶ 1,722:
alt = append(alt, sub)
return alt
}</
<code>expand_test.go</code>
<
import (
Line 1,842 ⟶ 1,807:
Expand(input)
}
}</
{{out}}
<pre>
Line 1,897 ⟶ 1,862:
ok rosetta_code/Brace_expansion 3.347s
</pre>
=={{header|Groovy}}==
{{trans|Java}}
<syntaxhighlight lang="groovy">class BraceExpansion {
static void main(String[] args) {
for (String s : [
"It{{em,alic}iz,erat}e{d,}, please.",
"~/{Downloads,Pictures}/*.{jpg,gif,png}",
"{,{,gotta have{ ,\\, again\\, }}more }cowbell!",
"{}} some }{,{\\\\{ edge, edge} \\,}{ cases, {here} \\\\\\\\\\}"
]) {
println()
expand(s)
}
}
static void expand(String s) {
expandR("", s, "")
}
private static void expandR(String pre, String s, String suf) {
int i1 = -1, i2 = 0
String noEscape = s.replaceAll("([\\\\]{2}|[\\\\][,}{])", " ")
StringBuilder sb = null
outer:
while ((i1 = noEscape.indexOf('{', i1 + 1)) != -1) {
i2 = i1 + 1
sb = new StringBuilder(s)
for (int depth = 1; i2 < s.length() && depth > 0; i2++) {
char c = noEscape.charAt(i2)
depth = (c == ('{' as char)) ? ++depth : depth
depth = (c == ('}' as char)) ? --depth : depth
if (c == (',' as char) && depth == 1) {
sb.setCharAt(i2, '\u0000' as char)
} else if (c == ('}' as char) && depth == 0 && sb.indexOf("\u0000") != -1) {
break outer
}
}
}
if (i1 == -1) {
if (suf.length() > 0) {
expandR(pre + s, suf, "")
} else {
printf("%s%s%s%n", pre, s, suf)
}
} else {
for (String m : sb.substring(i1 + 1, i2).split("\u0000", -1)) {
expandR(pre + s.substring(0, i1), m, s.substring(i2 + 1) + suf)
}
}
}
}</syntaxhighlight>
{{out}}
<pre>Itemized, please.
Itemize, please.
Italicized, please.
Italicize, please.
Iterated, please.
Iterate, please.
~/Downloads/*.jpg
~/Downloads/*.gif
~/Downloads/*.png
~/Pictures/*.jpg
~/Pictures/*.gif
~/Pictures/*.png
cowbell!
more cowbell!
gotta have more cowbell!
gotta have\, again\, more cowbell!
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}</pre>
=={{header|Haskell}}==
[http://www.reddit.com/r/readablecode/comments/1w6exe/p6_crosswalk_braceexpansionparses/cf229at "Here is a direct translation to Haskell using parsec"] (of [http://rosettacode.org/mw/index.php?title=Brace_expansion&oldid=175567#Raku an earlier version of the Raku solution]):
<
showExpansion :: String -> String
Line 1,944 ⟶ 1,982:
, "{,{,gotta have{ ,\\, again\\, }}more }cowbell!"
, "{}} some }{,{\\\\{ edge, edge} \\,}{ cases, {here} \\\\\\\\\\}"
]</
{{out}}
<pre>It{{em,alic}iz,erat}e{d,}, please.
Line 1,967 ⟶ 2,005:
{}} some }{\\ edge \,{ cases, {here} \\\\\}
{}} some }{\\ edge \,{ cases, {here} \\\\\}</pre>
=={{header|J}}==
Implementation:
<syntaxhighlight lang="j">
NB. legit { , and } do not follow a legit backslash:
legit=: 1,_1}.4>(3;(_2[\"1".;._2]0 :0);('\';a.);0 _1 0 1)&;:&.(' '&,)
Line 2,014 ⟶ 2,051:
options=. }:mask <;._1 y
prefix,each options,each suffix
)</
Examples:
<
~/Downloads/*.jpg
~/Downloads/*.gif
Line 2,039 ⟶ 2,076:
>expand t4
{}} some {\\edge }{ cases, here\\\}
{}} some {\\edgy }{ cases, here\\\}</
Explanation:
Line 2,048 ⟶ 2,085:
Finally, for each integer that we've used to mark delimiter locations, split out each of the marked options (each with a copy of that group's prefix and suffix). (Then when all that is done, take the absolute values convert back to unicode for the final result.)
=={{header|Java}}==
Should be able to handle all printable Unicode.
<
public static void main(String[] args) {
Line 2,096 ⟶ 2,132:
}
}
}</
<pre>Itemized, please.
Line 2,119 ⟶ 2,155:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}</pre>
=={{header|JavaScript}}==
Line 2,130 ⟶ 2,165:
Each node of the parse tree consists of one of two simple functions (AND: syntagmatic concatenation, OR: flattening of paradigms) with a set of arguments, each of which may be a plain string or an AND or OR subtree. The expansions are derived by evaluating the parse tree as an expression.
<
'use strict'
Line 2,320 ⟶ 2,355:
}).join('\n\n');
})();</
Value returned by function:
Line 2,356 ⟶ 2,391:
Sample of parse trees logged to the console:
<syntaxhighlight lang="javascript">{
"fn": "[function and]",
"args": [
Line 2,390 ⟶ 2,425:
" please."
]
}</
=={{header|jq}}==
''Adapted from [[#Wren|Wren]]''
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq'''
<syntaxhighlight lang=jq>
# Input: a string
# Emit an array of the expansions
def expand:
# Emit [ array, string ]
def getItem($depth):
def getGroup($depth):
{ out: [], comma: false, s: . }
| until (.s == "" or .return;
(.s | getItem($depth)) as $t
| $t[0] as $g
| .s = $t[1]
| if .s == "" then .return = [[], ""]
else .out += $g
| if .s[0:1] == "}"
then if .comma then .return = [.out, .s[1:]]
else .return = [ (.out | map( "{" + . + "}" )), .s[1:]]
end
else if .s[0:1] == ","
then .comma = true
| .s |= .[1:]
else .
end
end
end)
| if .return then .return else [[], ""] end ;
{ out: [""], s: .}
| until( (.s == "") or .return;
.c = .s[0:1]
| 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];
def inputs: [
"~/{Downloads,Pictures}/*.{jpg,gif,png}",
"It{{em,alic}iz,erat}e{d,}, please.",
"{,{,gotta have{ ,\\, again\\, }}more }cowbell!",
"{}} some }{,{\\\\{ edge, edge} \\,}{ cases, {here} \\\\\\\\\\}"
];
inputs[]
| "\n",
.,
" " + expand[]
</syntaxhighlight>
{{output}}
<pre>
~/{Downloads,Pictures}/*.{jpg,gif,png}
~/Downloads/*.jpg
~/Downloads/*.gif
~/Downloads/*.png
~/Pictures/*.jpg
~/Pictures/*.gif
~/Pictures/*.png
It{{em,alic}iz,erat}e{d,}, please.
Itemized, please.
Itemize, please.
Italicized, please.
Italicize, please.
Iterated, please.
Iterate, please.
{,{,gotta have{ ,\, again\, }}more }cowbell!
cowbell!
more cowbell!
gotta have more cowbell!
gotta have\, again\, more cowbell!
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Julia}}==
{{trans|Python}} <
out = [""]
while s != ""
Line 2,444 ⟶ 2,589:
println(ans)
end
end </
~/{Downloads,Pictures}/*.{jpg,gif,png}
--------------------------------------------
Line 2,478 ⟶ 2,623:
=={{header|Kotlin}}==
{{trans|Java}}
<
object BraceExpansion {
Line 2,529 ⟶ 2,674:
BraceExpansion.expand(s)
}
}</
{{out}}
Line 2,555 ⟶ 2,700:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Lua}}==
{{trans|Python}}
Note that this code isn't very memory efficient.
<syntaxhighlight lang="lua">local function wrapEachItem(items, prefix, suffix)
local itemsWrapped = {}
for i, item in ipairs(items) do
itemsWrapped[i] = prefix .. item .. suffix
end
return itemsWrapped
end
local function getAllItemCombinationsConcatenated(aItems, bItems)
local combinations = {}
for _, a in ipairs(aItems) do
for _, b in ipairs(bItems) do
table.insert(combinations, a..b)
end
end
return combinations
end
local getItems -- Forward declaration.
local function getGroup(s, pos, depth)
local groupItems = {}
local foundComma = false
while pos <= #s do
local items
items, pos = getItems(s, pos, depth)
if pos > #s then break end
for _, item in ipairs(items) do
table.insert(groupItems, item)
end
local c = s:sub(pos, pos)
if c == "}" then -- Possibly end of group.
if foundComma then return groupItems, pos+1 end
return wrapEachItem(groupItems, "{", "}"), pos+1 -- No group.
elseif c == "," then
foundComma, pos = true, pos+1
end
end
return nil -- No group.
end
function getItems(s, pos, depth)
local items = {""}
while pos <= #s do
local c = s:sub(pos, pos)
if depth > 0 and (c == "," or c == "}") then -- End of item in surrounding group.
return items, pos
end
local groupItems, nextPos = nil
if c == "{" then -- Possibly start of a group.
groupItems, nextPos = getGroup(s, pos+1, depth+1)
end
if groupItems then
items, pos = getAllItemCombinationsConcatenated(items, groupItems), nextPos
else
if c == "\\" and pos < #s then -- Escaped character.
pos = pos + 1
c = c .. s:sub(pos, pos)
end
items, pos = wrapEachItem(items, "", c), pos+1
end
end
return items, pos
end
local tests = [[
~/{Downloads,Pictures}/*.{jpg,gif,png}
It{{em,alic}iz,erat}e{d,}, please.
{,{,gotta have{ ,\, again\, }}more }cowbell!
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}
]]
for test in tests:gmatch"[^\n]+" do
print(test)
for _, item in ipairs(getItems(test, 1, 0)) do
print("\t"..item)
end
print()
end</syntaxhighlight>
{{out}}
<pre>
~/{Downloads,Pictures}/*.{jpg,gif,png}
~/Downloads/*.jpg
~/Downloads/*.gif
~/Downloads/*.png
~/Pictures/*.jpg
~/Pictures/*.gif
~/Pictures/*.png
...
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">(*The strategy is to first capture all special sub-expressions and reformat them so they are semantically clear. The built in function Distribute could then do the work of creating the alternatives, but the order wouldn't match that given in the instructions (although as a set the alternatives would be correct). I'll take a more complicated route so as to follow the instructions exactly.*)
(*A few named constants for readability.*)
EscapeToken="\\";(*In Mathematica, backslash is an escape character when inputing a string, so we need to escape it.*)
LeftBraceToken="{";
RightBraceToken="}";
(*This basically sequesters escaped substrings so that they don't get matched during later processing.*)
CaptureEscapes[exp:{___String}]:=SequenceReplace[exp,{EscapeToken,x_}:>EscapeToken<>x];
(*Any remaining braces are un-escaped. I'm "unstringifying" them to more easily pick them out during later processing.*)
CaptureBraces[exp:{___String}]:=ReplaceAll[exp,{LeftBraceToken->LeftBrace,RightBraceToken->RightBrace}];
(*Building up trees for the braced expressions. Extra braces are just raw data, so transform them back to strings.*)
CaptureBraceTrees[exp:{(_String|LeftBrace|RightBrace)...}]:=ReplaceAll[FixedPoint[SequenceReplace[{LeftBrace,seq:(_String|_BraceTree)...,RightBrace}:>BraceTree[seq]],exp],{LeftBrace->LeftBraceToken,RightBrace->RightBraceToken}];
(*At thie point, we should have an expression with well-braced substructures representing potential alternatives. We must expand brace trees to alternatives in the correct order.*)
ExpandBraceTrees[exp:Expr[head___String,bt_BraceTree,tail___]]:=ReplaceAll[Thread[Expr[head,ToAlternatives[bt],tail]],alt_Alt:>Sequence@@alt];
ExpandBraceTrees[exp:Expr[___String]]:={exp};
ExpandBraceTrees[exps:{__Expr}]:=Catenate[ExpandBraceTrees/@exps];
(*If there are no commas, then it's a literal sub-expression. Otherwise, it's a set of alternatives.*)
ToAlternatives[bt_BraceTree]:={LeftBraceToken<>StringJoin@@bt<>RightBraceToken}/;FreeQ[bt,","];
ToAlternatives[BraceTree[","]]=ToAlternatives[BraceTree["",",",""]];
ToAlternatives[bt:BraceTree[",",__]]:=ToAlternatives[Prepend[bt,""]];
ToAlternatives[bt:BraceTree[__,","]]:=ToAlternatives[Append[bt,""]];
ToAlternatives[bt_BraceTree]:=Alt@@@SequenceSplit[List@@bt,{","}];
NormalizeExpression=Apply[Expr]@*CaptureBraceTrees@*CaptureBraces@*CaptureEscapes@*Characters;
BraceExpand[str_String]:=ReplaceAll[FixedPoint[ExpandBraceTrees,NormalizeExpression[str]],Expr->StringJoin];
(*Data was stored in a local file.*)
BraceTestData=ReadList[FileNameJoin[{NotebookDirectory[],"BraceTestData.txt"}],String];BraceTestData//TableForm</syntaxhighlight>
<pre>~/{Downloads,Pictures}/*.{jpg,gif,png}
It{{em,alic}iz,erat}e{d,}, please.
{,{,gotta have{ ,\, again\, }}more }cowbell!
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}</pre>
{{out}}
<pre>Column[Column /@ BraceExpand /@ BraceTestData, Left, 2]</pre>
<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|Nim}}==
{{trans|Seed7}}
<syntaxhighlight lang="nim">proc expandBraces(str: string) =
var
escaped = false
depth = 0
bracePoints: seq[int]
bracesToParse: seq[int]
for idx, ch in str:
case ch
of '\\':
escaped = not escaped
of '{':
inc depth
if not escaped and depth == 1:
bracePoints = @[idx]
of ',':
if not escaped and depth == 1:
bracePoints &= idx
of '}':
if not escaped and depth == 1 and bracePoints.len >= 2:
bracesToParse = bracePoints & idx
dec depth
else:
discard
if ch != '\\':
escaped = false
if bracesToParse.len > 0:
let prefix = str[0..<bracesToParse[0]]
let suffix = str[(bracesToParse[^1] + 1)..^1]
for idx in 1..bracesToParse.high:
let option = str[(bracesToParse[idx - 1] + 1)..(bracesToParse[idx] - 1)]
expandBraces(prefix & option & suffix)
else:
echo " ", str
#———————————————————————————————————————————————————————————————————————————————————————————————————
when isMainModule:
for str in ["It{{em,alic}iz,erat}e{d,}, please.",
"~/{Downloads,Pictures}/*.{jpg,gif,png}",
"{,{,gotta have{ ,\\, again\\, }}more }cowbell!",
"{}} some }{,{\\\\{ edge, edge} \\,}{ cases, {here} \\\\\\\\\\}"]:
echo "\nExpansions of \"", str, "\":"
expandBraces(str)</syntaxhighlight>
{{out}}
<pre>
Expansions of "It{{em,alic}iz,erat}e{d,}, please.":
Itemized, please.
Italicized, please.
Iterated, please.
Itemize, please.
Italicize, please.
Iterate, please.
Expansions of "~/{Downloads,Pictures}/*.{jpg,gif,png}":
~/Downloads/*.jpg
~/Pictures/*.jpg
~/Downloads/*.gif
~/Pictures/*.gif
~/Downloads/*.png
~/Pictures/*.png
Expansions of "{,{,gotta have{ ,\, again\, }}more }cowbell!":
cowbell!
more cowbell!
gotta have more cowbell!
gotta have\, again\, more cowbell!
Expansions of "{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}":
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}</pre>
=={{header|Perl}}==
Line 2,563 ⟶ 2,966:
So here is a manual solution that implements the specification precisely:
<
my $input = shift;
my @stack = ([my $current = ['']]);
Line 2,603 ⟶ 3,006:
return @$current;
}</
Usage demonstration:
<
chomp($input);
print "$input\n";
Line 2,617 ⟶ 3,020:
It{{em,alic}iz,erat}e{d,}, please.
{,{,gotta have{ ,\, again\, }}more }cowbell!
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}</
{{out}}
<pre>
Line 2,647 ⟶ 3,050:
</pre>
=={{header|Phix}}==
Fairly straightforward recursive solution
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Brace_expansion.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">pair</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">stems</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">brest</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: #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;">stems</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;">brest</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;">stems</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">brest</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: #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;">function</span> <span style="color: #000000;">brarse</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;">integer</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">idx</span><span style="color: #0000FF;"><=</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;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'{'</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">alts</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">}</span>
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">l0</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">idx</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">nest</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bl0</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">level</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">idx</span><span style="color: #0000FF;"><=</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: #008080;">switch</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'{'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">level</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">nest</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">'}'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">level</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">bl0</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">level</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">','</span><span style="color: #0000FF;">:</span> <span style="color: #008080;">if</span> <span style="color: #000000;">level</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">alts</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alts</span><span style="color: #0000FF;">,</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">)</span>
<span
<span style="color: #008080;">case</span> <span style="color: #008000;">'\\'</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span
<span style="color: #008080;">if</span> <span style="color: #000000;">bl0</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: #000000;">idx</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;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alts</span><span style="color: #0000FF;">)></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">level</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">alts</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">idx</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">stems</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">stem</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">alts</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</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;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alts</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">rest</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">alts</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">alts</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</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: #000000;">nest</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">inners</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">brarse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rest</span><span style="color: #0000FF;">)</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;">inners</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">stems</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stems</span><span style="color: #0000FF;">,</span><span style="color: #000000;">stem</span><span style="color: #0000FF;">&</span><span style="color: #000000;">inners</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;">else</span>
<span style="color: #000000;">stems</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stems</span><span style="color: #0000FF;">,</span><span style="color: #000000;">stem</span><span style="color: #0000FF;">&</span><span style="color: #000000;">rest</span><span style="color: #0000FF;">)</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;">pair</span><span style="color: #0000FF;">(</span><span style="color: #000000;">stems</span><span style="color: #0000FF;">,</span><span style="color: #000000;">brarse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$]))</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">nest</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">pair</span><span style="color: #0000FF;">({</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">l0</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]},</span><span style="color: #000000;">brarse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">l0</span><span style="color: #0000FF;">..$]))</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: #000000;">idx</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;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000080;font-style:italic;">-- (since ? and pp() add their own backslash escapes:)</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">edump</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">x</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;">x</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</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"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</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;">procedure</span>
<span style="color: #000000;">edump</span><span style="color: #0000FF;">(</span><span style="color: #000000;">brarse</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"~/{Downloads,Pictures}/*.{jpg,gif,png}"</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">edump</span><span style="color: #0000FF;">(</span><span style="color: #000000;">brarse</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"It{{em,alic}iz,erat}e{d,}, please."</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">edump</span><span style="color: #0000FF;">(</span><span style="color: #000000;">brarse</span><span style="color: #0000FF;">(</span><span style="color: #008000;">`{,{,gotta have{ ,\, again\, }}more }cowbell!`</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">edump</span><span style="color: #0000FF;">(</span><span style="color: #000000;">brarse</span><span style="color: #0000FF;">(</span><span style="color: #008000;">`{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}`</span><span style="color: #0000FF;">))</
<!--</syntaxhighlight>-->
{{Out}}
<pre>
Line 2,744 ⟶ 3,147:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|PHP}}==
{{trans|Python}}
<
$out = [''];
while ($s) {
Line 2,820 ⟶ 3,222:
printf(" %s\n", $expansion);
}
}</
{{out}}
<pre>
Line 2,849 ⟶ 3,251:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|PicoLisp}}==
<
(let Lst
(make
Line 2,882 ⟶ 3,283:
(if (pair (car Lst))
(mapcan recurse (car Lst))
(list (car Lst)) ) ) ) ) ) ) )</
Test:
<
(quote
"~/Downloads/*.jpg"
Line 2,916 ⟶ 3,317:
"{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}"
"{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}" )
(braceExpand "{}} some }{,{\\\\{ edge, edge} \\,}{ cases, {here} \\\\\\\\\\}") )</
=={{header|PowerShell}}==
{{works with|PowerShell|2}}
<syntaxhighlight lang="powershell">
function Expand-Braces ( [string]$String )
{
Line 2,976 ⟶ 3,376:
}
}
</syntaxhighlight>
<syntaxhighlight lang="powershell">
$TestStrings = @(
'It{{em,alic}iz,erat}e{d,}, please.'
Line 2,992 ⟶ 3,392:
Expand-Braces $String
}
</syntaxhighlight>
{{out}}
<pre>
Line 3,025 ⟶ 3,425:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Prolog}}==
<syntaxhighlight lang="prolog">
sym(',', commalist) --> ['\\',','], !.
sym(H, Context) --> [H], { not(H = '{'; H = '}'), (Context = commalist -> not(H = ','); true) }.
syms([H|T], Context) --> sym(H, Context), !, syms(T, Context).
syms([], _) --> [].
symbol(Symbol, Context) --> syms(Syms,Context), {atom_chars(Symbol, Syms)}.
braces(Member) --> ['{'], commalist(List), ['}'], {length(List, Len), Len > 1, member(Member, List)}.
commalist([H|T]) --> sym_braces(H, commalist), [','], commalist(T).
commalist([H]) --> sym_braces(H, commalist).
sym_braces(String, Context) --> symbol(S1, Context), braces(S2), sym_braces(S3, Context), {atomics_to_string([S1,S2,S3],String)}.
sym_braces(String, Context) --> braces(S1), symbol(S2, Context), sym_braces(S3, Context), {atomics_to_string([S1,S2,S3],String)}.
sym_braces(String, Context) --> symbol(String, Context).
sym_braces(String, _) --> braces(String).
sym_braces(String, Context) --> ['{'], sym_braces(S2, Context), {atomics_to_string(['{',S2],String)}.
sym_braces(String, Context) --> ['}'], sym_braces(S2, Context), {atomics_to_string(['}',S2],String)}.
grammar(String) --> sym_braces(String, braces).
brace_expansion(In, Out) :- atom_chars(In, Chars), findall(Out,grammar(Out, Chars, []), List), list_to_set(List, Out).
</syntaxhighlight>
Testing:
<syntaxhighlight lang="prolog">
?- brace_expansion("~/{Downloads,Pictures}/*.{jpg,gif,png}", Out).
Out = ["~/Downloads/*.jpg","~/Downloads/*.gif","~/Downloads/*.png","~/Pictures/*.jpg","~/Pictures/*.gif","~/Pictures/*.png"].
?- brace_expansion("It{{em,alic}iz,erat}e{d,}, please.", Out).
Out = ["Itemized, please.", "Itemize, please.", "Iterated, please.", "Iterate, please.", "Italicized, please.", "Italicize, please."].
?- brace_expansion("{,{,gotta have{ ,\\, again\\, }}more }cowbell!", Out).
Out = ["cowbell!", "more cowbell!", "gotta have more cowbell!", "gotta have, again, more cowbell!"].
</syntaxhighlight>
=={{header|Python}}==
<
out = [""]
while s:
Line 3,066 ⟶ 3,502:
{,{,gotta have{ ,\, again\, }}more }cowbell!
{}} some }{,{\\\\{ edge, edge} \,}{ cases, {here} \\\\\\\\\}'''.split('\n'):
print "\n\t".join([s] + getitem(s)[0]) + "\n"</
{{out}}
Line 3,097 ⟶ 3,533:
</pre>
=={{header|Racket}}==
{{trans|Python}}
<
(require racket/match)
(define (merge-lists as . bss)
Line 3,149 ⟶ 3,584:
))
(for ((s (in-list patterns)) #:when (printf "expand: ~a~%" s) (x (in-list (brace-expand s))))
(printf "\t~a~%" x)))</
{{out}}
<pre>expand: ~/{Downloads,Pictures}/*.{jpg,gif,png}
Line 3,173 ⟶ 3,608:
{}} some }{,{\\ edge ,}{ cases, {here} \\\\}
{}} some }{,{\\ edge ,}{ cases, {here} \\\\}</pre>
=={{header|Raku}}==
(formerly Perl 6)
Line 3,181 ⟶ 3,615:
On the other end, we recursively walk the parse tree returning expanded sublists, and we do the cartesian concatenation of sublists at each level by use of the <tt>X~</tt> operator, which is a "cross" metaoperator used on a simple <tt>~</tt> concatenation. As a list infix operator, <tt>X~</tt> does not care how many items are on either side, which is just what you want in this case, since some of the arguments are strings and some are lists. Here we use a fold or reduction form in square brackets to interpose the cross-concat between each value generated by the map, which returns a mixture of lists and literal strings. One other thing that might not be obvious: if we bind to the match variable, <tt>$/</tt>, we automatically get all the syntactic sugar for its submatches. In this case, <tt>$0</tt> is short for <tt>$/[0]</tt>, and represents all the submatches captured by 0th set of parens in either <tt>TOP</tt> or <tt>alt</tt>. <tt>$<meta></tt> is likewise short for <tt>$/<meta></tt>, and retrieves what was captured by that named submatch.
<syntaxhighlight lang="raku"
token TOP { ( <meta> | . )* }
token meta { '{' <alts> '}' | \\ . }
Line 3,223 ⟶ 3,657:
a{b,{{c}}
{a{\}b,c}d
END</
{{out}}
<pre>~/{Downloads,Pictures}/*.{jpg,gif,png}
Line 3,286 ⟶ 3,720:
{a\}bd
{acd</pre>
=={{header|REXX}}==
<
* Brace expansion
* 26.07.2016
Line 3,495 ⟶ 3,928:
Say arg(1) /* show on screen */
Call lineout oid,arg(1) /* write to file */
Return</
{{out}}
<pre>J:\>rexx braces
Line 3,542 ⟶ 3,975:
{}
1 {}</pre>
=={{header|Ruby}}==
{{trans|Python}}
<
out = [""]
until s.empty?
Line 3,585 ⟶ 4,017:
puts getitem(s)[0].map{|str| "\t"+str}
puts
end</
{{out}}
Line 3,615 ⟶ 4,047:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Rust}}==
<
const CLOSE_CHAR: char = '}';
const SEPARATOR: char = ',';
Line 3,800 ⟶ 4,231:
println!("{}", line);
}
}</
Line 3,835 ⟶ 4,266:
{{trans|Python}}
<
fn main() {
let input = "~/{Downloads,Pictures}/*.{jpg,gif,png}
Line 3,916 ⟶ 4,347:
None
}
</syntaxhighlight>
{{out}}
Line 3,943 ⟶ 4,374:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Scala}}==
{{works with|Scala|2.11}}
<
import collection.mutable.ListBuffer
case class State(isChild: Boolean, alts: ListBuffer[String], rem: List[Char])
Line 3,977 ⟶ 4,407:
parseElem(State(false, ListBuffer(""), s.toList)).alts
}
</syntaxhighlight>
Demonstrating:
<
println(expand("""~/{Downloads,Pictures}/*.{jpg,gif,png}""") mkString "\n")
println(expand("It{{em,alic}iz,erat}e{d,}, please.") mkString "\n")
println(expand("""{,{,gotta have{ ,\, again\, }}more }cowbell!""") mkString "\n")
println(expand("""{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}""") mkString "\n")
</syntaxhighlight>
{{out}}
<pre>
Line 4,006 ⟶ 4,436:
{}} some }{,\\ edge \,{ cases, {here} \\\\\}
</pre>
=={{header|Scheme}}==
<syntaxhighlight lang="scheme">
(define (parse-brackets str)
;; We parse the bracketed strings using an accumulator and a stack
Line 4,099 ⟶ 4,528:
(bracket-expand "It{{em,alic}iz,erat}e{d,}")
;; '("Ited" "Ite" "Itemed" "Iteme" "Italiced" "Italice" "Itized" "Itize" "Iterated" "Iterate")
</syntaxhighlight>
=={{header|Seed7}}==
<
const proc: expandBraces (in string: stri) is func
Line 4,161 ⟶ 4,589:
expandBraces(stri);
end for;
end func;</
{{out}}
Line 4,188 ⟶ 4,616:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Sidef}}==
{{trans|Perl}}
<
var current = ['']
var stack = [[current]]
Line 4,252 ⟶ 4,679:
It{{em,alic}iz,erat}e{d,}, please.
{,{,gotta have{ ,\, again\, }}more }cowbell!
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}</
{{out}}
<pre>
Line 4,281 ⟶ 4,708:
{}} some }{,{\\ edge \,}{ cases, {here} \\\\\}
</pre>
=={{header|Simula}}==
{{trans|Python}}
<
BEGIN
Line 4,370 ⟶ 4,796:
END;
END;</
ARRAYLISTS
BEGIN
Line 4,520 ⟶ 4,946:
END
</syntaxhighlight>
{{out}}
<pre>~/{Downloads,Pictures}/*.{jpg,gif,png}
Line 4,549 ⟶ 4,975:
</pre>
=={{header|Tailspin}}==
<
templates braceExpansion
composer braceParse
Line 4,564 ⟶ 4,989:
templates collateSequence
data part <[]|''> local
@: [''];
$... -> #
$@!
when <´part´ '.*'> do
def part: $;
@: [$@... -> '$;$part;'];
Line 4,585 ⟶ 5,011:
'{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}' -> '"$;" expands to $ -> braceExpansion ... -> '$#10;$;';$#10;$#10;' -> !OUT::write
</syntaxhighlight>
{{out}}
<pre>
Line 4,617 ⟶ 5,043:
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
<
proc combine {cases1 cases2 {insert ""}} {
Line 4,686 ⟶ 5,112:
}
return $current
}</
Demonstrating:
<
"~/{Downloads,Pictures}/*.{jpg,gif,png}"
"It{{em,alic}iz,erat}e{d,}, please."
Line 4,695 ⟶ 5,121:
} {
puts $testcase\n\t[join [commatize $testcase] \n\t]
}</
{{out}}
<pre>
Line 4,721 ⟶ 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}}
<syntaxhighlight lang="vbnet">Module Module1
Function GetGroup(s As String, depth As Integer) As Tuple(Of List(Of String), String)
Dim out As New List(Of String)
Dim comma = False
While Not String.IsNullOrEmpty(s)
Dim gs = GetItem(s, depth)
Dim g = gs.Item1
s = gs.Item2
If String.IsNullOrEmpty(s) Then
Exit While
End If
out.AddRange(g)
If s(0) = "}" Then
If comma Then
Return Tuple.Create(out, s.Substring(1))
End If
Return Tuple.Create(out.Select(Function(a) "{" + a + "}").ToList(), s.Substring(1))
End If
If s(0) = "," Then
comma = True
s = s.Substring(1)
End If
End While
Return Nothing
End Function
Function GetItem(s As String, Optional depth As Integer = 0) As Tuple(Of List(Of String), String)
Dim out As New List(Of String) From {""}
While Not String.IsNullOrEmpty(s)
Dim c = s(0)
If depth > 0 AndAlso (c = "," OrElse c = "}") Then
Return Tuple.Create(out, s)
End If
If c = "{" Then
Dim x = GetGroup(s.Substring(1), depth + 1)
If Not IsNothing(x) Then
Dim tout As New List(Of String)
For Each a In out
For Each b In x.Item1
tout.Add(a + b)
Next
Next
out = tout
s = x.Item2
Continue While
End If
End If
If c = "\" AndAlso s.Length > 1 Then
c += s(1)
s = s.Substring(1)
End If
out = out.Select(Function(a) a + c).ToList()
s = s.Substring(1)
End While
Return Tuple.Create(out, s)
End Function
Sub Main()
For Each s In {
"It{{em,alic}iz,erat}e{d,}, please.",
"~/{Downloads,Pictures}/*.{jpg,gif,png}",
"{,{,gotta have{ ,\, again\, }}more }cowbell!",
"{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}"
}
Dim fmt = "{0}" + vbNewLine + vbTab + "{1}"
Dim parts = GetItem(s)
Dim res = String.Join(vbNewLine + vbTab, parts.Item1)
Console.WriteLine(fmt, s, res)
Next
End Sub
End Module</syntaxhighlight>
{{out}}
<pre>It{{em,alic}iz,erat}e{d,}, please.
Itemized, please.
Itemize, please.
Italicized, please.
Italicize, please.
Iterated, please.
Iterate, please.
~/{Downloads,Pictures}/*.{jpg,gif,png}
~/Downloads/*.jpg
~/Downloads/*.gif
~/Downloads/*.png
~/Pictures/*.jpg
~/Pictures/*.gif
~/Pictures/*.png
{,{,gotta have{ ,\, again\, }}more }cowbell!
cowbell!
more cowbell!
gotta have more cowbell!
gotta have\ again\ more cowbell!
{}} some }{,{\\{ edge, edge} \,}{ cases, {here} \\\\\}
{}} some }{,{\ edge \}{ cases, {here} \\\
{}} some }{,{\ edge \}{ cases, {here} \\\</pre>
=={{header|Wren}}==
{{trans|Python}}
<
var getItem = Fn.new { |s, depth|
Line 4,789 ⟶ 5,427:
for (s in getItem.call(input, 0)[0]) System.print(" " + s)
System.print()
}</
{{out}}
Line 4,822 ⟶ 5,460:
=={{header|zkl}}==
This is a two pass algorithm (2*length(string)), one pass to find valid {} pairs, the next pass to expand them.
<
cs:=L();
foreach c in (code){ // start fresh or continue (if recursing)
Line 4,853 ⟶ 5,491:
}
strings
}</
<
"It{{em,alic}iz,erat}e{d,}, please.", "a{2,1}b{X,Y,X}c", 0'|a\\{\\\{b,c\,d}|,
"{a,b{c{,{d}}e}f", 0'|{,{,gotta have{ ,\, again\, }}more }cowbell!|,
Line 4,860 ⟶ 5,498:
{
"%s expands to\n %s".fmt(bs,expando(bs)).println();
}</
{{out}}
<pre>
|