I suppose that the set of answers won't be complete without the contribution of a cryptic RegularExpression
...
$pattern = RegularExpression["\\\\newcommand({([^{}]|(?1))*})(?1)"];
The pattern works for simple cases:
StringCases[#, $pattern]& @
"XXX\\newcommand{ABC}{DEF}XXX\\newcommand{GHI}{JKL}XXX\\newcommand{MNO}{PQR}"
(* { "\\newcommand{ABC}{DEF}",
"\\newcommand{GHI}{JKL}",
"\\newcommand{MNO}{PQR}" } *)
... and more complicated cases:
StringCases[#, $pattern]& @
"\\newcommand{XXX{ABC}XXX{DEF}XXX}{XXX{GHI}XXX}\\newcommand{JKL}{MNO}\\oldcommand{XXX}"
(* { "\\newcommand{XXX{ABC}XXX{DEF}XXX}{XXX{GHI}XXX}",
"\\newcommand{JKL}{MNO}" } *)
... and even cases with nested occurrences:
StringCases[#, $pattern]& @
"\\newcommand{ABC}{\\newcommand{DEF}{\\newcommand{GHI}{JKL}}}\\oldcommand{XXX}{XXX}"
(* { "\\newcommand{ABC}{\\newcommand{DEF}{\\newcommand{GHI}{JKL}}}" } *)
If desired, we can use Overlaps -> True
to extract those nested cases as well:
StringCases[#, $pattern, Overlaps -> True]& @
"\\newcommand{ABC}{\\newcommand{DEF}{\\newcommand{GHI}{JKL}}}\\oldCommand{XXX}{XXX}"
(* { "\\newcommand{ABC}{\\newcommand{DEF}{\\newcommand{GHI}{JKL}}}",
"\\newcommand{DEF}{\\newcommand{GHI}{JKL}}",
"\\newcommand{GHI}{JKL}" } *)
What Does All This Gibberish Mean?
Let's consider the pattern in detail:
RegularExpression["\\\\newcommand({([^{}]|(?1))*})(?1)"]
\\\\
matches a single backslash. The desired single backslash is escaped once to account for Mathematica string syntax. Each resulting backslash must then be escaped a second time to account for regular expression syntax. Thus we end up with four backslashes. newcommand
, of course, matches that self-same literal text.
The main part of the pattern, in outline, looks like this: ({...})(?1)
. {...}
matches some text surrounded by braces. This pattern is "captured" by wrapping it with parentheses: ({...})
. This pattern is then re-used by inserting a back-reference to it: (?1)
. The significance of the 1 is that it is referencing the #1 (i.e. first) capture group. Note that (?1)
does not refer to the text matched by the first pattern, but rather it refers to the pattern itself. The construction will match different text from the first occurrence, but according to the same pattern.
Now let's return to the subpattern which we elided above: ([^{}]|(?1))*
. This defines a second capture group containing alternatives which can be repeated zero or more times, (...|...)*
. Each occurrence must be either a non-brace character ([^{}]
) or any text that matches that outer pattern #1 that we captured earlier.
Purists will note that we do not need to capture these inner alternatives, so the inner group should really be expressed as a non-capturing group, (?:...)*
. This detail is largely irrelevant in practice, so I opted to reduce the amount of line noise in the pattern.
Using Named Patterns For Safety
As discussed in (72724), using positional pattern back-references such as (?1)
can sometimes give unpredictable results in Mathematica. We can change the pattern to use named back-references for safety:
$pattern2 = RegularExpression["\\\\newcommand(?P<x>{([^{}]|(?P>x))*})(?P>x)"];
StringCases[#, $pattern2, Overlaps -> True]& @
"\\newcommand{ABC}{\\newcommand{DEF}{\\newcommand{GHI}{JKL}}}"
(* { "\\newcommand{ABC}{\\newcommand{DEF}{\\newcommand{GHI}{JKL}}}",
"\\newcommand{DEF}{\\newcommand{GHI}{JKL}}",
"\\newcommand{GHI}{JKL}" } *)
The first capture group (...)
is replaced by the syntax (?P<x>...)
which assigns the name x to the group. Each pattern back-reference (?1)
is then replaced with an explicit back-reference to that name, (?P>x)
.
{"\\newcommand{ABC{asdas}{asdsad}"}
for secondstrnig
in v8.0, 9.0, 10.0 and 10.1. $\endgroup$