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}

enter image description here


Here's a LuaLaTeX-based solution.

enter image description here

% !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

Tags:

Macros