Pass a macro (with arguments) as an argument for another macro

enter image description here

xstring replacements do not work by expansion, but they need the input string to be expanded, thus adding \expandafter doesn't really help. You need to use the optional argument so that the string with the replacement is stored in a temporary macro, then you can use \expandafter to expand that macro to pass to the second call. In addition as it fully expands its input in a way not entirely consistent with LaTeX \protect mechanism I needed to make \$ e-tex protected.

\documentclass{article}

\usepackage{xstring} % for StrSubstitute

\let\olddollar\$
\protected\def\${\olddollar}


\newcommand*{\changeslash}[1] {%
    \StrSubstitute{#1}{/}{5c}[\temp]%
}
\newcommand*{\changedollars}[1] {%
    \StrSubstitute{#1}{\$}{24}[\temp]%
}
\newcommand*{\changeboth}[1] {%
  \changedollars{#1}%
  \expandafter\changeslash\expandafter{\temp}%
}


\begin{document}


\changeslash{aaa/b\$bb}\temp


\changedollars{aaa/b\$bb}\temp


\changeboth{aaa/b\$bb}\temp

\end{document} 

The problem seems to rely in two settings that you should apply:

\noexpandargs
\exploregroups

If I give your definitions and use those declarations, from

\changeboth{A/B\$C}

I get that LaTeX prints

A5cB24C

which seems what you're expecting. However you'll have no way to retrieve the modified string. If instead you want to store the result in a macro for later usage, a different approach should be used.

\documentclass{article}
\usepackage{xstring} % for StrSubstitute

\newcommand*{\changeslash}[1]{%
    \StrSubstitute{#1}{/}{5c}[\temp]%
}
\newcommand*{\changedollars}[1]{%
    \StrSubstitute{#1}{\$}{24}[\temp]%
}
\newcommand*{\changeboth}[1]{%
  \changedollars{#1}%
  \expandafter\changeslash\expandafter{\temp}%
}

\begin{document}
\noexpandarg
\changeboth{A/B\$C}

\show\temp
\end{document}

This will produce no output, but TeX will print on the terminal

> \temp=macro:
->A5cB24C.
l.18 \show\temp

and you can freely use the changed string. Here \exploregroups is not needed.


A different approach uses LaTeX3 features.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% Document commands
\NewDocumentCommand{\changeslash}{ m }
 {
  \baitisj_change_slash:n { #1 }
 }
\NewDocumentCommand{\changedollars}{ m }
 {
  \baitisj_change_dollars:n { #1 }
 }
\NewDocumentCommand{\printchangedstring}{}
 {
  \tl_use:N \l_baitisj_string_tl
 }
\NewDocumentCommand{\changeboth}{ m }
 {
  \baitisj_change_dollars:n { #1 }
  \baitisj_change_slash:V \l_baitisj_string_tl
 }

% Variables and functions
\tl_new:N \l_baitisj_string_tl
\cs_new_protected:Npn \baitisj_change_slash:n #1
 {
  \tl_set:Nn \l_baitisj_string_tl { #1 }
  \tl_replace_all:Nnn \l_baitisj_string_tl { / } { 5c }
 }
\cs_new_protected:Npn \baitisj_change_dollars:n #1
 {
  \tl_set:Nn \l_baitisj_string_tl { #1 }
  \tl_replace_all:Nnn \l_baitisj_string_tl { \$ } { 24 }
 }
\cs_generate_variant:Nn \baitisj_change_slash:n { V }

\ExplSyntaxOff

\begin{document}

\changeboth{A/B\$C}
\printchangedstring

\end{document}

The scheme for extending this to more substitutions seems clear. It depends on your application using \printchangedstring or using the modified string in other ways.

Note In any case (xstring or xparse method), if you need to change the literal $ into 24, don't use \$, but simply $.


Citing from the xstring documentation explains why your approach does not work:

When full expansion mode is activated with \fullexpandarg, arguments are expanded with an \edef before they are read by the macro.

The macros of this package are not purely expandable, i.e. they cannot be put in the argument of an \edef. Nestling macros is not possible neither.

So this probably does not really help you, but you might have something to look for. It might be easier to help you from here on, if you would state a question.

Tags:

Macros