I am trying to implement a command that parses some expression that can be a mix of plain text, commands with their (any number of) arguments, or even -- if I understood that correctly -- unexpandable parts.
To the end of parsing, I wish to scan the input 'item' by 'item', where an item is either a single char, maybe a {} pair, any command along with its arguments, or a single unexpandable stuff.
My first attempt was to recursively scan the input with :
\NewDocumentCommand\scan{m u{\relax}}{%
#1%
\ifblank{#2}
{}{,\scan#2\relax}%
}
that renders a,b,c,d
for \scan abcd\relax
.
However, commands must be wrapped for them to work, as in : \scan a{\vec x}bcd\relax
, which correctly renders a,x,b,c,d
(where x has a vector arrow). Depending on how they are defined, even nullary commands need wrapping.
This requirement is very annoying to me so I wish to get rid of it.
Furthermore, a wrapped {⋅⋅⋅}
would eventually need recursive parsing so protecting commands with it is ultimately not acceptable since it wouldn't fix the issue anymore.
My second attempt was to use xstring on the input, unfortunately it only works with plain text.
My third attempt was to detokenize/retokenize. But I can't find how to make \tokenize
work, and didn't find documentation on it : \tokenize{\detokenize{⋅⋅⋅}}
for instance yields unrelated errors. Also I'm not convinced this would lead to a practical solution since that would leave me with the problem of grabbing commands with all their arguments, not mentionning the potential trouble of spaces removal.
Finally, I went back to the first attempt but with \expandafter
in the hope of transforming a command and its arguments into a unique 'solid' thing, as in :
\NewDocumentCommand\scan{m u{\relax}}{%
#1%
\ifblank{#2}
{}{,\expandafter\scan#2\relax}%
}
\NewDocumentCommand\scanit{m}{%
\expandafter\scan#1\relax%
}
Which I can't get to compile when input contains commands, for instance I would like \(scanit {\vec abcd}\)
to render a,b,c,d
(where a has a vector arrow), but I get : Extra }, or forgotten $. \(\scanit {\vec abcd}\)
. In fact, there are cases where it doesn't work but it would without \expandafter
-- e.g. with some nullaries.
Obviously I'm not in control of everything i'm doing here, so any explanation is appreciated
abcd
anda\vec{b}cd
as use cases, which should be rendered asa, b, c, d
anda, \vec{b}, c, d
. Are groups of single letters and macros the only possible use cases? If not, please provide some additional examples.Use of \next doesn't match its definition. \scanit{a{$\vec b$}cde}
. Bytheway, my goal is to not have to wrap thevec b