Etoolbox 等效:通过宏定义控制序列

Etoolbox 等效:通过宏定义控制序列

当使用普通宏名称时,我可以将宏的值设置为

\newcommand*{\SetMacro}[1]{\def#1{42}}

\SetMacro{\Answer}

并将\Answer具有值42。有没有etoolbox办法调用\SetMacro。比如

\SetMacro{\csuse{Answer for Section Y}}%% <--- This is incorrect

没有改变的定义\SetMacro

下面的代码产生:

在此处输入图片描述

如果没有办法,那么需要使用etoolbox什么等效魔法来调用\expandafter\SetMacro

笔记:

  • 解决这个问题的一种方法是定义\SetMacro*如下所示。想知道是否有一种方法不需要修改\SetMacro

代码:

\documentclass{article}
\usepackage{etoolbox}

\newcommand*{\SetMacro}[1]{%
    %% #1 macro name to be set
    \def#1{42}% After much calculations in this macro
}

\begin{document}
\textbf{Using macro}:
\SetMacro{\Answer}
Answer is \Answer.

\par\medskip
\textbf{Not using macro (with csname)}:
\csdef{Answer for Section X}{42}
Answer is \csuse{Answer for Section X}.

\par\medskip
\textbf{Using macro (with csname)}:
%\SetMacro{\??????{Answer for Section Y}}%% <--- How to do this???
Answer is \csuse{Answer for Section Y}.
\end{document}

解决方案(使用修改后的\SetMacro

\documentclass{article}
\usepackage{etoolbox}
\usepackage{xparse}

\NewDocumentCommand{\SetMacro}{%
    s% 
    m% macro or control sequence name
}{%
    \IfBooleanTF{#1}{%
        \csdef{#2}{42}% After much calculations in this macro
    }{%
        \def#2{42}% After much calculations in this macro
    }%
}%

\begin{document}
\textbf{Using macro}:
\SetMacro{\Answer}
Answer is \Answer.

\par\medskip
\textbf{Not using macro (with csname)}:
\csdef{Answer for Section X}{42}
Answer is \csuse{Answer for Section X}.

\par\medskip
\textbf{Using macro (with csname)}:
\SetMacro*{Answer for Section Y}%% <--- One possible way
Answer is \csuse{Answer for Section Y}.
\end{document}

答案1

为了那个原因精确的您要求的情况您可以做到\SetMacro{\x{}\csdef{Answer for Section Y}}

因为我们把\SetMacro=放在了结尾处,然后添加了后面跟着的。这样就剩下了。所以你让第一个做一些无害的事情,然后调用你自己的。\def#1{42}#1\x{}\def\csdef{Answer for Section Y}{42}\def\x{}\csdef{Answer for Section Y}{42}\def\csdef

如果你允许\expandafter你可以做

\def\usecsinsteadofthetokenitself#1{\x{}\csdef{#1}}

然后\expandafter\SetMacro\expandafter{\usecsinsteadofthetokenitself{Answer for Section Y}}输出与之前相同的内容。

但这只是为了“娱乐目的”,肯定无论您的问题是什么,都一定有另一种解决方案。

答案2

或许如此,但是你的目标是有些神秘。

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\SetMacro}{m}
 {
  \bool_lazy_and:nnTF
   {
    \tl_if_single_p:n { #1 }
   }
   {
    \token_if_cs_p:N #1
   }
   { \cs_new:Npn #1 } { \cs_new:cpn { #1 } } { 42 }
 }

\NewExpandableDocumentCommand{\use}{m}{\use:c { #1 }}

\ExplSyntaxOff

\begin{document}

\SetMacro{\test}
\SetMacro{This is another test}
\SetMacro{z}

\test

\use{This is another test}

\use{z}

\end{document}

这将打印 42 三次。

如果参数是单个标记(即控制序列),则测试返回 true。当然,诸如此类的愚蠢输入\SetMacro{a\bc}将会失败。

答案3

\documentclass{article}
\usepackage{etoolbox}
\newcommand*{\SetMacro}[1]{\testtype#1\endtt\expandafter\def\argname{42}}
\def\testtype#1#2\endtt{%
  \ifx\csname#1%
    \expandafter\def\expandafter\argname\expandafter{#1#2}\else%
    \ifx\csuse#1%
      \expandafter\def\expandafter\argname\expandafter{\csname#2\endcsname}%
    \else%
      \def\argname{#1#2}%
    \fi%
  \fi}
\begin{document}
\SetMacro{\Answer} \Answer

\SetMacro{\csname A3\endcsname} \csname A3\endcsname

\SetMacro{\csuse{B21}} \csuse{B21}
\end{document}

在此处输入图片描述

为了使其更有趣,\SetMacro可以采用 2 个参数,其中第二个参数是#1定义的

\documentclass{article}
\usepackage{etoolbox}
\newcommand*{\SetMacro}[2]{\testtype#1\endtt\expandafter\def\argname{#2}}
\def\testtype#1#2\endtt{%
  \ifx\csname#1%
    \expandafter\def\expandafter\argname\expandafter{#1#2}\else%
    \ifx\csuse#1%
      \expandafter\def\expandafter\argname\expandafter{\csname#2\endcsname}%
    \else%
      \def\argname{#1#2}%
    \fi%
  \fi}
\begin{document}
\SetMacro{\Answer}{41} \Answer

\SetMacro{\csname A3\endcsname}{42} \csname A3\endcsname

\SetMacro{\csuse{B21}}{43} \csuse{B21}
\end{document}

在此处输入图片描述

答案4

仅需要单个\expandafter链“进入第一个参数”的 方法:\SetMacro

\documentclass{article}
\usepackage{etoolbox}

%%===============================================================================
%% Define a mechanism where in expansion-contexts a single "hit" by \expandafter
%% triggers K "hits" by \expandafter.
%%------------------------------------------------------------------------------- 
%% Syntax of that mechanism is:
%% 
%% \romannumeral\Expandtimes{<number K>}<token sequence> 
%% ->
%% K times the leading token of <token sequence> will be "hit" by \expandafter .
%% 
%% In expansion contexts the leading \romannumeral being "hit" by one 
%% \expandafter is sufficient for obtaining these K "hits" by \expandafter
%% on the leading token of <token sequence>.
%%
%% In expansion contexts instead of several \expandafter-chains going
%% to the leading token of <token sequence>, you need only one 
% \expandafter-chain going to the token \romannumeral.
%%
\begingroup
\makeatletter
\@firstofone{%
  \endgroup
  \newcommand\innerdfork{}\def\innerdfork#1d#2#3dd{#2}%
  \newcommand*\dfork[1]{\innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd}%
  \newcommand*\Expandtimes[1]{%
    0\expandafter\innerExp
     \expandafter{%
     \expandafter}%
     \romannumeral\number\number#1 000d%
  }%
  \newcommand*\innerExp[2]{\dfork{#2}{#1 }{\innerExp{#1#1\expandafter}}}%
}%


\newcommand*{\SetMacro}[1]{\def#1}%

\parskip=\bigskipamount
\parindent=0ex

\begin{document}

\SetMacro{\Answer}{42}%
\verb|\SetMacro{\Answer}{42}|\\
\(\to\)\\
\texttt{\string\Answer:~\meaning\Answer}

With \verb|\csname..\endcsname| one expansion-step is required for obtaining the control-sequence-token. Thus:

\expandafter\SetMacro\expandafter{\csname Answer\endcsname}{43}%
\verb|\expandafter\SetMacro\expandafter{\csname Answer\endcsname}{43}|\\
\(\to\)\\
\texttt{\string\Answer:~\meaning\Answer}


With \verb|\csuse{...}| three expansion-steps are required for obtaining the control-sequence-token. Thus:

\expandafter\SetMacro\expandafter{\romannumeral\Expandtimes{3}\csuse{Answer}}{44}%
\verb|\expandafter\SetMacro\expandafter{\romannumeral\Expandtimes{3}\csuse{Answer}}{44}|\\
\(\to\)\\
\texttt{\string\Answer:~\meaning\Answer}

\end{document}

在此处输入图片描述

相关内容