I have a macro which uses inner macros to process pairs of arguments. The essential part can be broken down to
\mymacro{\inside{A}{1};\inside{B}{2},\inside{C}{3}}
.
Originally I had all pairs processed and then printed, separated by commas, using a sequence to get an output like "1A, 2B, 3C", "1A, 2B" or "1A", for three, two and one arguments, respectively.
Now the requirements have changed and I need the output to be: "1,A 2,B 3.C", "1,A 2.B" or "1.A".
I figured, this could be done with sequences and came up with this solution:
\documentclass{article}
\usepackage{xparse,expl3} % expl3 loaded explicitly - not necessary because it is already loaded by xparse
\ExplSyntaxOn
\tl_new:N \l__map_current_tl
\tl_new:N \l__map_tl
\tl_new:N \l__inside_tl
\seq_new:N \l__my_seq
\seq_new:N \l__second_seq
\NewDocumentCommand \mymacro {>{\SplitList{;}} m}
{
\mymacro_process_func:n {#1}
\mymacro_output_func:n
\\
}
\NewDocumentCommand \inside {m m}
{
\inside_process_func:nn {#1} {#2}
}
\cs_new_protected:Npn \inside_process_func:nn #1 #2
{
\tl_if_empty:NTF \l__inside_tl
{ \tl_put_right:Nn \l__inside_tl {#2 !! #1} }
{ \tl_put_right:Nn \l__inside_tl {~ #2 !! #1} }
}
\cs_new_protected:Npn \mymacro_process_func:n #1
{
% make sure token lists and sequences are empty
\tl_clear:N \l__map_current_tl
\tl_clear:N \l__map_tl
\tl_clear:N \l__inside_tl
\seq_clear:N \l__my_seq
\seq_clear:N \l__second_seq
\tl_map_function:nN {#1} \mymacro_map_func:n
\tl_show:N {\l__map_tl}
\seq_set_split:NnV \l__my_seq {;} \l__map_tl
% \seq_show:N \l__my_seq
\seq_use:Nnnn \l__my_seq {} {} {}
}
\cs_new_protected:Npn \mymacro_map_func:n #1
{
\tl_set:Nn \l__map_current_tl {#1}
\tl_if_empty:NTF \l__map_tl
{ \tl_set_eq:NN \l__map_tl \l__map_current_tl }
{
\tl_put_right:Nn \l__map_tl {;}
\tl_put_right:NV \l__map_tl \l__map_current_tl
}
\tl_set:Nn \l__map_current_tl {#1}
}
\cs_new_protected:Npn \mymacro_output_func:n
{
\seq_set_split:NnV \l__second_seq {!!} \l__inside_tl
% \seq_show:N \l__second_seq
\seq_use:Nnnn \l__second_seq {.} {,} {.}
}
\ExplSyntaxOff
\begin{document}
Achieved:\\
\mymacro{\inside{A}{1}}
\mymacro{\inside{A}{1};\inside{B}{2}}
\mymacro{\inside{A}{1};\inside{B}{2};\inside{C}{3}}
Desired:\\
1.A \\ 1,A 2.B \\ 1,A 2,B 3.C
\end{document}
As you can see, the code does what it should:
However, I fear it is not very efficient and it looks very dubious to me. For example, I used \l__my_seq
in \mymacro_process_func:n
with spaces in a previous version:
\seq_set_split:NnV \l__my_seq {;} \l__map_tl
\seq_use:Nnnn \l__my_seq {~} {~} {~}
but the spaces did not appear in the output. (In fact, replacing all ~
by ?
prints none, one or two question marks before the output, respectively.)
- Is there a better (shorter) way to without the need to change the use of
\mymacro
and\inside
? (I can't change all the macros in my document) - Is there, in general, a better approach to this problem?
By the way: I am not sure if my solution (naming, etc.) complies with all rules and conventions, so any comment on this is appreciated as well.