8

In Pass a command as argument for another command, a notion of invoking TeX macros as methods was described. In my case, I'm attempting to use arguments within the call structure. My example below uses two passes of \StrSubstitute to replace characters that I want to modify:

\usepackage{xstring} % for StrSubstitute

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

I've experimented with adding \expandafter in different places, but this problem has me stumped.

2
  • Hi baitisj Welcome to TeX.SE! I edited your question just to make the link more descriptive, if you'd prefer it your way, feel free to roll back :)
    – cmhughes
    Sep 30, 2012 at 18:51
  • Thank you, for both the welcome, and for the edit, cmhughes! As a new user of LaTeX (and of TeX.SE), I'm grateful.
    – baitisj
    Oct 1, 2012 at 3:35

3 Answers 3

7

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} 
2
  • This worked beautifully, and I think it's clear enough that a newbie like me can begin to understand what is going on. I really appreciate the help, Dr. Carlisle!
    – baitisj
    Oct 1, 2012 at 21:26
  • In the example using StrSubstitute I am unable to wrap the result of change both with texttt. \texttt{\changeboth{A/B\$C}} Any suggestions?
    – DHH
    Sep 23, 2020 at 15:07
6

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 $.

2

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .