a^b ---> \macro{a}{b}
The code should be self-explaining:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\test}{m}
{
\projetmbc_test:n { #1 }
}
\tl_new:N \l__projetmbc_test_tl
\cs_new_protected:Nn \projetmbc_test:n
{
\tl_set:Nn \l__projetmbc_test_tl { #1 }
\regex_replace_all:nnN
{ (\cB. .*? \cE.|[[:alpha:]])\^ } % search a braced group or single letter followed by ^
{ \c{projetmbc_power:nn} \1 } % prepend \projetmbc_power:nn and remove ^
\l__projetmbc_test_tl
\ensuremath { \tl_use:N \l__projetmbc_test_tl }
}
\cs_new:Nn \projetmbc_power:nn
{
\prg_replicate:nn { #2 } { #1 }
}
\ExplSyntaxOff
\begin{document}
\test{x} % ---> x
\test{x y} % ---> x y
\test{x y^2} % ---> x y y
\test{x^3 y^2 z} % ---> x x x y y z
\test{{x_1}^3 {abcde}^2}
\end{document}
Here's a LuaLaTeX-based solution.
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{amsmath} % for '\ensuremath' macro
\usepackage{luacode} % for 'luacode' env. and '\luastringN' macro
\begin{luacode}
function test ( s )
s = s:gsub ( "(\\%a+) ^(%d+)", string.rep ) -- e.g., '\alpha^3'
s = s:gsub ( "(%a)^(%d+)" , string.rep ) -- e.g., 'x^2'
s = s:gsub ( "(%b{})^(%d+)" , string.rep ) -- e.g., '{x_1}^4'
tex.sprint ( s )
end
\end{luacode}
% Define a LaTeX wrapper macro:
\newcommand\test[1]{\directlua{test(\luastringN{#1})}}
\begin{document}
\obeylines
\test{$x$}
\test{$x y$}
\test{$x^1 y^12$}
\test{$x^3 y^2 z$}
\test{${x_1}^3 {abcde}^2$} % courtesy of @egreg's posting
\test{$\alpha^2\lambda^3\omega^4$}
\end{document}
You can also do it fully-expandably in expl3
by absorbing tokens one-by-one. This ignores spaces, but since you are planning to use this for partial derivatives in math mode, that shouldn't be a problem. It might be quite slow, though. It also doesn't work recursively, i.e. \test{{x^3}}
will not be repeated.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \mbc_process_powers:w #1 #2 #3 {
\str_if_eq:nnF { #1 } { \q_stop }
{
\str_if_eq:nnTF { #2 } { ^ }
{
\prg_replicate:nn { #3 } { #1 }
\mbc_process_powers:w
} {
#1 \mbc_process_powers:w { #2 } { #3 }
}
}
}
\NewExpandableDocumentCommand \test { m }
{
\mbc_process_powers:w #1 \q_stop \q_stop \q_stop
}
\ExplSyntaxOff
\begin{document}
\ttfamily % nicer font for \meaning
\edef\x{\test{x}} \meaning\x % ---> x
\edef\x{\test{x y}} \meaning\x % ---> xy
\edef\x{\test{x y^2}} \meaning\x % ---> xyy
\edef\x{\test{x^3 y^2 z}} \meaning\x % ---> xxxyyz
\edef\x{\test{{abcd}^4 or {x_1}^3}} \meaning\x % ---> abcdabcdabcdabcdorx_1x_1x_1
\end{document}
If you can't or don't want to use expl3
, you can also implement it in normal LaTeX, but you'll need a few helper macros:
\makeatletter
\protected\def\@qstop{\@qstop}
\ifdefined\directlua
% LuaTeX doesn't have \pdfstrcmp.
\directlua{
function pdfstrcmp(a, b)
if a < b then
tex.sprint("-1")
elseif a > b then
tex.sprint("1")
else
tex.sprint("0")
end
end
}
\long\def\pdfstrcmp#1#2{\directlua{pdfstrcmp("\luaescapestring{#1}", "\luaescapestring{#2}")}}
\fi
\def\@ifstrequal#1#2{%
\ifnum\pdfstrcmp{\unexpanded{#1}}{\unexpanded{#2}}=0
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\def\replicate#1#2{%
\ifnum\numexpr#1\relax>0
#2%
\expandafter\replicate\expandafter{\number\numexpr(#1)-1\relax}{#2}%
\fi
}
\def\processpowers#1#2#3{%
\@ifstrequal{#1}{\@qstop}{}{%
\@ifstrequal{#2}{^}{%
\replicate{#3}{#1}%
\processpowers
}{%
#1\processpowers{#2}{#3}%
}%
}%
}
\newcommand\test[1]{\processpowers#1\@qstop\@qstop\@qstop}
\makeatother