扩展字符串替换宏中的参数

扩展字符串替换宏中的参数

重写为最小非工作示例:

\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}应该扩展为ACBD但是却扩展为ABCD

答案1

\substitute在使用此命令之前,您需要完全扩展的参数。这可以安排,但不能使用\@for不可扩展的映射。由于您已经在使用,所以xparse我只会在中写入它expl3。有关详细信息,请参阅代码注释:

\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}

相关内容