Expand an argument into a string
This does work via expansion so as shown works in \typeout
as well as the typeset paragraph.
\documentclass{article}
\def\zz#1{\zzz#1(\relax)}
\def\zzz#1(#2){\zzA{#1}\ifx\relax#2\else(\zzA{#2})\expandafter\zzz\fi}
\def\zzA#1{\ifnum\numexpr0#1\relax>0 A\expandafter\zzA\expandafter{\the\numexpr#1-1\relax}\fi}
\begin{document}
\zz{3(2)2(1)}
\typeout{\zz{3(2)2(1)}}
\end{document}
puts
AAA(AA)AA(A)
on the terminal.
Here's an expandable approach using expl3
. \Replicate[<tokens>]{<token list>}
It will loop over your input <token list>
looking for any sequence of digits and replacing them by that amount of repetitions of the input <tokens>
(by default A
). Everything else that is not a digit will be just forwarded to the output, so you can have things like
\Replicate{3(2)2(1)}
\Replicate[Z]{3(2)2(1)}
\Replicate[(Z)]{3(2)2(1)}
\Replicate[Z]{3 \textbf{(2) 2}( 1 )}
\edef\zzzzzzzzzzzz{\Replicate[Z]{3\textbf{(2)2}(1)}}
\texttt{\meaning\zzzzzzzzzzzz}
produce:
Here's the code:
\documentclass{article}
\usepackage{xparse}
\pagestyle{empty}
\ExplSyntaxOn
\NewExpandableDocumentCommand \Replicate { O{A} m }
{ \perror_replicate:nn {#1} {#2} }
\cs_new:Npn \perror_replicate:nn #1 #2
{
\__perror_replicate_loop:w #2
\q_recursion_tail \q_recursion_stop {#1} { }
}
\cs_new:Npn \__perror_replicate_loop:w #1 \q_recursion_stop
{
\tl_if_head_is_N_type:nTF {#1}
{ \__perror_replicate_parse_token:N }
{
\tl_if_head_is_group:nTF {#1}
{ \__perror_replicate_nested:n }
{ \__perror_replicate_output_space:w }
}
#1 \q_recursion_stop
}
\use:nn { \cs_new:Npn \__perror_replicate_output_space:w } { ~ }
{ \__perror_replicate_output:nw { ~ } }
\cs_new:Npn \__perror_replicate_output:nw #1 #2 \q_recursion_stop #3 #4
{ \__perror_replicate_loop:w #2 \q_recursion_stop {#3} { #4 #1 } }
\cs_new:Npn \__perror_replicate_nested:n #1 #2 \q_recursion_stop #3
{
\exp_args:Ne \__perror_replicate_output:nw
{ { \perror_replicate:nn {#3} {#1} } }
#2 \q_recursion_stop {#3}
}
\cs_new:Npn \__perror_replicate_end:nn #1 #2 { \exp_not:n {#2} }
\cs_new:Npn \__perror_replicate_parse_token:N #1
{
\quark_if_recursion_tail_stop_do:Nn #1
{ \__perror_replicate_end:nn }
\__perror_replicate_if_digit:NTF #1
{ \__perror_replicate_collect_number:nw }
{ \__perror_replicate_output:nw }
{#1}
}
\prg_new_conditional:Npnn \__perror_replicate_if_digit:N #1 { TF }
{
\if_int_compare:w 10 < 9 \token_to_str:N #1 \exp_stop_f:
\prg_return_true:
\else:
\prg_return_false:
\fi:
}
\cs_new:Npn \__perror_replicate_collect_number:nw #1 #2 \q_recursion_stop
{
\tl_if_head_is_N_type:nTF {#2}
{ \__perror_replicate_collect_number:nN }
{ \__perror_replicate_finish_number:nw }
{#1} #2 \q_recursion_stop
}
\cs_new:Npn \__perror_replicate_collect_number:nN #1 #2
{
\quark_if_recursion_tail_stop_do:Nn #2
{
\__perror_replicate_finish_number:nw {#1}
\q_recursion_tail \q_recursion_stop
}
\__perror_replicate_if_digit:NTF #2
{ \__perror_replicate_collect_number:nw { #1 #2 } }
{ \__perror_replicate_finish_number:nw {#1} #2 }
}
\cs_new:Npn \__perror_replicate_finish_number:nw #1 #2 \q_recursion_stop #3
{
\exp_args:Ne \__perror_replicate_output:nw
{ \prg_replicate:nn {#1} {#3} }
#2 \q_recursion_stop {#3}
}
\ExplSyntaxOff
\begin{document}
\Replicate{3(2)2(1)}
\Replicate[Z]{3(2)2(1)}
\Replicate[(Z)]{3(2)2(1)}
\Replicate[Z]{3 \textbf{(2) 2}( 1 )}
\edef\zzzzzzzzzzzz{\Replicate[Z]{3\textbf{(2)2}(1)}}
\texttt{\meaning\zzzzzzzzzzzz}
\end{document}
A piece of cake using LuaLaTeX (but yes, only works with LuaLaTeX):
\documentclass{standalone}
\usepackage{luacode}
\newcommand\myexpand[2]{%
\directlua{local function myexpand(x,s) return (x:gsub("(\csstring\%d+)", function(u) return s:rep(math.floor(u)) end)) end tex.sprint(myexpand(\luastring{#1},\luastring{#2}))}}
\begin{document}
\myexpand{(3)2(2)1}{A}
\end{document}