Here is my solution using Mathematica and the package FunctionalParsers.m available at GitHub. This solution might not look very pretty. And used infix notation in order to get shorter code.
Import["https://raw.githubusercontent.com/antononcube/MathematicaForPrediction/master/FunctionalParsers.m"]
varNameParser =
ParseApply[StringJoin,
ParseMany1[
ParsePredicate[
StringLength[#] > 0 && StringMatchQ[#, WordCharacter] &]]];
varSequenceParser = ParseListOf[varNameParser, ParseSymbol[","]];
fArgsParser = ParseApply[#[[1]] <> "[" <> Riffle[#[[2]], ","]
<> "]" &, (varNameParser \[LeftTriangle]
ParseSymbol[","])\[CircleTimes]ParseBracketed[
ParseSymbol[","] \[RightTriangle] (varSequenceParser)]];
fParser =
ParseSymbol["f"] \[RightTriangle]
ParseBracketed[ParseCurlyBracketed[fArgsParser]];
fsListParser =
ParseCurlyBracketed[ParseListOf[fParser, ParseSymbol[","]]];
The result from applying the last parser, fsListParser, to:
argStr = "{f[{m,[,1,2,3,]}],f[{x,[,y,]}],f[{c,[,a,b,]}]}"
is this:
{{{}, {"m[1,2,3,]", "x[y,]", "c[a,b,]"}}}
I am not sure how satisfying this final result is. I am mostly trying to illustrate the use of Functional Parsers (or parser combinators) for this kind of problem. In short, the parsing recognizes the pattern and the pattern is being acted upon using ParseApply.
Let us look at what the parsers do in turn.
varNameParser -- parsing a sequence of letters and numbers as an entity.
In[243]:= varNameParser[{"a", "b"}]
Out[243]= {{{}, "ab"}}
varSequenceParser -- parsing a list of entities.
Here we get several alternatives of successful parsing. The first one is the one we want.
In[274]:= varSequenceParser[Characters["ab,1232,x"]]
Out[274]= {{{}, {"ab", "1232", "x"}}, {{",", "1", "2", "3", "2", ",",
"x"}, {"ab"}}, {{"a", "b", ",", "1", "2", "3", "2", ",", "x"}, {}}}
fArgsParser -- parses the internal arguments of f.
This parser also applies a function to the parsed result using ParseApply. (The comma after "m" shows that my implementation of ParseListOf has a bug.)
In[275]:= fArgsParser[Characters["x,[,y,m,]"]]
Out[275]= {{{}, "x[y,m,]"}}
fParser -- parse an instance of f[__] .
In[234]:= fParser[Characters["f[{x,[,y,]}]"]]
Out[234]= {{{}, "x[y,]"}}
fsListParser -- parse a list of f terms.
In[305]:= fsListParser[Characters[argStr]]
Out[305]= {{{}, {"m[1,2,3,]", "x[y,]", "c[a,b,]"}}}
The output of fsListParser in 5 is a list of strings not a string. If we want a string for the output we can modify fsListParser with ParseApply:
fsListParser =
ParseCurlyBracketed[
ParseApply[
"{" <> StringJoin @@ Riffle[#, ","] <> "}" &,
ParseListOf[fParser, ParseSymbol[","]]]];
Now we obtain a string:
In[293]:= fsListParser[Characters[argStr]]
Out[293]= {{{}, "{m[1,2,3,],x[y,],c[a,b,]}"}}
This might seem quite messy. I am not sure is this solution the easiest, but it is quite universal. I find this technique quite powerful.
The package FunctionalParsers.m can generate parsers from BNF specifications. I opted of writing the parsers directly in order to better illustrate the technique. The functional parsers can be relatively easily implemented in any functional language. (I have made implementations in Mathematica, R, and Lua.) Scala has functional parsers included in it. There are packages for C# and Java.
This blog post of mine has explanations and references on functional parsers application: Natural language processing with functional parsers . This presentation has technical details: Functional parsers for an integration requests language .
mathematicaandlisptags. Give some usage examples. $\endgroup$