当使用普通宏名称时,我可以将宏的值设置为
\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}