![\newcommand 的参数作为变量名?](https://linux22.com/image/346730/%5Cnewcommand%20%E7%9A%84%E5%8F%82%E6%95%B0%E4%BD%9C%E4%B8%BA%E5%8F%98%E9%87%8F%E5%90%8D%EF%BC%9F.png)
我有以下情况:我想使用 的参数\newcommand
作为新变量的名称,我在\newcommand
使用中定义该变量\def
。
当我尝试编译时,它总是说我新定义的变量不存在。我认为问题出在命令中的参数的“#”符号上\def
。
\documentclass{article}
\newcounter{src}
\newcommand{\src}[1]{\stepcounter{src}\def \#1 {\arabic{src}} [\arabic{src}]}
\begin{document}
\src{testone}
\src{testtwo}
first test: \testone
second test: \testtwo
\end{document}
我的预期输出是:
1 2 第一次测试:1 第二次测试:2
但我得到的却是:
! Undefined control sequence. \testone
! Undefined control sequence. \testtwo
有人知道如何使用#
作为变量名吗?
答案1
命令序列名称的构造可以使用
\csname #1\endcsname
但这对于 来说还不够\def
,必须先加上\expandafter
,以扩展序列名称,然后使用\def
(对于 等也同样如此\edef
)
IE:
\expandafter\def\csname #1\endcsname{some expansion stuff}
\def\foo{some expansion stuff}
如果#1
包含 foo,则会扩展为。
我\edef
在这里使用定义宏名时的计数器数字,否则\arabic{src}
会打印当前数字。
\documentclass{article}
\newcounter{src}
\newcommand{\src}[1]{\stepcounter{src}\expandafter\edef\csname#1\endcsname {\arabic{src}} [\arabic{src}]}
\begin{document}
\src{testone}
\src{testtwo}
first test: \testone
second test: \testtwo
\end{document}
答案2
Christian Hupfer 很好地解释了发生的事情。您可能会喜欢基于 的不同方法expl3
。
使用的主要函数是\cs_new:cpx
,它是 的变体\cs_new:Npn
。
cs
代表“控制序列”new
不言自明:
将函数名称与签名,即其参数列表N
代表单个 tokenp
代表“参数文本”(在下面的示例中为空)n
代表“支撑参数”(替换文本)
变体是\cs_new:cpx
wherec
表示我们期望一个带括号的参数,它将被转换为一个以反斜杠开头的单个符号标记;x
instead 表示相应的参数将被完全展开。我们需要完全展开,因为我们想要存储计数器的当前值,而不是生成该值的指令。
其他函数是\int_new:N
分配一个新的类型int
(整数)变量并\int_gincr:N
全局增加该变量。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% allocate a new integer variable
\int_new:N \g_philipp_src_int
% the main command
\NewDocumentCommand{\src}{m}
{
% step the integer variable
\int_gincr:N \g_philipp_src_int
% define \#1 with expansion of the replacement text
\cs_new:cpx { #1 } { \int_to_arabic:n { \g_philipp_src_int } }
% print the current value
[\int_to_arabic:n { \g_philipp_src_int }]
}
\ExplSyntaxOff
\begin{document}
\src{testone}
\src{testtwo}
first test: \testone
second test: \testtwo
\end{document}
答案3
作为另一种选择,您可以使用包etoolbox
。该包提供了很多有用的命令和钩子。
在你的情况下,命令\csdef
很有用,它由 定义etoolbox
。这类似于基督教的解决方案。
\documentclass{article}
\newcounter{src}
\usepackage{etoolbox}
\newcommand{\src}[1]{\stepcounter{src}\csedef{#1}{\arabic{src}}[\arabic{src}]}
\begin{document}
\src{testone}
\src{testtwo}
first test: \testone
second test: \testtwo
\end{document}
答案4
您可以使用该包参考值使内容可在整个文档中使用 — — 类似于 LaTeX 2ε 的\label
— —\ref
机制。
\documentclass{article}
\usepackage[unicode=true]{hyperref}
\usepackage{zref}
\makeatletter
\@ifpackageloaded{hyperref}{%
\@ifdefinable\RetrieveNumber@RefUndefText{%
\DeclareRobustCommand\RetrieveNumber@RefUndefText{%
\texorpdfstring{\nfss@text{\reset@font\bfseries ??}}{??}%
}%
}%
\@ifdefinable\RetrieveNumber{%
\DeclareRobustCommand\RetrieveNumber[1]{%
\texorpdfstring{\zref@refused{#1}}{}%
\zref@extractdefault{#1}{numbertostore}{\RetrieveNumber@RefUndefText}%
}%
}%
}{%
\@ifdefinable\RetrieveNumber@RefUndefText{%
\DeclareRobustCommand\RetrieveNumber@RefUndefText{%
\nfss@text{\reset@font\bfseries ??}%
}%
}%
\@ifdefinable\RetrieveNumber{%
\DeclareRobustCommand\RetrieveNumber[1]{%
\zref@refused{#1}%
\zref@extractdefault{#1}{numbertostore}{\RetrieveNumber@RefUndefText}%
}%
}%
}%
%
\zref@newprop{numbertostore}[0]{0}%
\@ifdefinable\src{%
\DeclareRobustCommand\src[1]{%
\stepcounter{src}%
\begingroup
\zref@setcurrent{numbertostore}{\arabic{src}}%
\zref@labelbyprops{#1}{numbertostore}%
\endgroup
\RetrieveNumber{#1}%
}%
}%
\makeatother
\newcounter{src}
\begin{document}
first test: \RetrieveNumber{testone}
second test: \RetrieveNumber{testtwo}
\src{testone}
\src{testtwo}
first test: \RetrieveNumber{testone}
second test: \RetrieveNumber{testtwo}
\end{document}