\newcommand 的参数作为变量名?

\newcommand 的参数作为变量名?

我有以下情况:我想使用 的参数\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

  1. cs代表“控制序列”
  2. new不言自明
  3. :将函数名称与签名,即其参数列表
  4. N代表单个 token
  5. p代表“参数文本”(在下面的示例中为空)
  6. n代表“支撑参数”(替换文本)

变体是\cs_new:cpxwherec表示我们期望一个带括号的参数,它将被转换为一个以反斜杠开头的单个符号标记;xinstead 表示相应的参数将被完全展开。我们需要完全展开,因为我们想要存储计数器的当前值,而不是生成该值的指令。

其他函数是\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}

在此处输入图片描述

相关内容