2

Rewritten as minimum non-working example:

\documentclass{article}

\makeatletter
\usepackage{xstring}
\usepackage{xparse}

\newcommand\textfromcase[1]{%
    \IfEqCase{#1}{% for the purposes of this example:
        {0}{AB} % \textfromcase[0] expands to AB
        {1}{CD} % \textfromcase[1] expands to CD
        % and many more lines of this kind.
}}

\newcommand{\EscSubstitute}[2]{\expandafter\StrSubstitute\expandafter{\x}{#1}{#2}[\x]}
\newcommand\substitute[1]{{%
    \noexpandarg% because I otherwise get weird error messages.
    \StrSubstitute{#1}{BC}{CB}[\x]% replacements for example.
    \EscSubstitute{PQ}{QP}% many more lines of this kind.
    \x}}

\newcommand{\concatenate}[1]{%
   \substitute{\@for \el:=#1\do{\textfromcase{\el}}}%
}
\makeatother

\begin{document}
\substitute{ABCD} = ACBD.

\concatenate{1,0} = CDAB.

\concatenate{0,1} $\neq$ ACBD!
\end{document}

\concatenate{0,1} should expand to ACBD but instead expands to ABCD.

  • We probably need a bit more detail here. The obvious thing to do is simply fully expand the argument to \substitute but you've deliberately disabled much the same idea for \StrSubstitute using \noexpandarg. That makes me suspect there is more to the arguments here than simple text. Can you give more detail? Also, at present we have to guess what packages you are using: a full minimal working example (MWE) would be useful. – Joseph Wright Nov 20 '14 at 9:13
  • I'd probably do then entire process here just using expl3, by the way. – Joseph Wright Nov 20 '14 at 9:13
  • Made a minimum working example (i.e. added the first 4 and last 6 non-empty lines). \noexpandarg is because it gives me weird error messages otherwise. I tried using expl3, but couldn't get it done that way, either. – user66554 Nov 20 '14 at 17:19
  • There is an important difference between your initial snippets and the full MWE: that \@for part. That explains why you've used \noexpandarg so I can hopefully provide a solution. – Joseph Wright Nov 20 '14 at 17:51
  • No, it doesn't, the \@for was from my in-between attempts at finding another solution. With the \@for, the error message on leaving out the \noexpandarg is different, but in either case there is an error. – user66554 Nov 20 '14 at 18:15
2

You need to fully expand the argument of \substitute before you use this command. That can be arranged but not with a \@for mapping, which is non-expandable. As you are already using xparse I'd just write this in expl3. See code comments for details:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
% User command taking ones comma-list argument
\NewDocumentCommand \concatenate { > { \SplitList { , } } m }
  {
    % Use an x-type expansion with an expandable argument to force
    % expansion here
    \user_substitute:x
      {
        \tl_map_function:nN {#1} \user_text_from_case:n
      }
  }
% A simple document-level wrapper around a code-level function
\NewDocumentCommand \substitute { m }
  { \user_substitute:n {#1} }
% The code-level substitution command is built to be flexible
\cs_new_protected:Npn \user_substitute:n #1
  {
    \group_begin:
      \tl_set:Nn \l__user_tmp_tl {#1}
      \tl_map_inline:nn
        {
          % A list of pairs for substitution: could be in a separate
          % tl or comma list depending on requirements
          { { BC } { CB } }
          { { PQ } { QP } }
        }
        { \__user_substitute_aux:nn ##1 }
    \exp_last_unbraced:NV \group_end:
    \l__user_tmp_tl
  }
\cs_generate_variant:Nn \user_substitute:n { x }
\cs_new_protected:Npn \__user_substitute_aux:nn #1#2
  { \tl_replace_all:Nnn \l__user_tmp_tl {#1} {#2} }
\tl_new:N \l__user_tmp_tl
% An expandable case function to do first replacements
% Again, the list itself could be in a separate variable if required
\cs_new:Npn \user_text_from_case:n #1
  {
    \str_case:nn {#1}
      {
        { 0 } { AB }
        { 1 } { CD }
      }
  }

% For outdated expl3 installations
\cs_if_exist:NF \str_case:nn
  {
    \cs_new:Npn \str_case:nn #1#2
      { \prg_case_str:nnn {#1} {#2} }
  }
\ExplSyntaxOff

\begin{document}
\substitute{ABCD} = ACBD.

\concatenate{1,0} = CDAB.

\concatenate{0,1} $\neq$ ACBD!
\end{document}
  • That results in: Undefined control sequence: \user_text_from_case:n #1->\str_case:nn – user66554 Nov 20 '14 at 18:12
  • @user66554 You have an older version of expl3 installed. We are pretty clear that we only support the latest version, but I'll add a check for the older code. – Joseph Wright Nov 20 '14 at 19:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.