16

I have the following situation: I want to use the argument of \newcommand to be the name of a new variable, which I define within \newcommand using \def.

When I try to compile it always says that my newly defined variable doesn't exist. I think the problem is the "#"-symbol of the argument within the \def command.

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

My expected output would be:

1 2 first test: 1 second test: 2

But instead I get:

! Undefined control sequence. \testone
! Undefined control sequence. \testtwo

Does anyone have a solution for how to use the # for a variable name?

2
  • Welcome to TeX.SX Try \expandafter\def\csname#1\endcsname instead of \def \#1. But your counter number will be wrong anyway. It will use the current counter value, so it must be expanded, e.g. \edef, for example
    – user31729
    Dec 27, 2016 at 22:14
  • Please consider to accept one of the given answers here!
    – user31729
    Jan 29, 2017 at 14:09

4 Answers 4

19

The construction of command sequence names can be done with

\csname #1\endcsname

but this is not sufficient for \def, it must be prepended with \expandafter, to expand the sequence name first, then use \def (the same holds for \edef etc.)

i.e.:

\expandafter\def\csname #1\endcsname{some expansion stuff}

will expand to \def\foo{some expansion stuff} if #1 contains foo.

I used \edef here to use the counter number at the time of definition of the macro name, otherwise \arabic{src} would print the current number.

\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}
8
  • This seems to work, thanks a lot! However, when executing \src I get a big space in front of [number]. How can I get rid of this?
    – Philipp
    Dec 27, 2016 at 22:26
  • Of course this will not work this way if #1 has a `\` in it
    – user31729
    Dec 27, 2016 at 22:26
  • @Philipp: Which big space? There is only the usual paragraph indentation
    – user31729
    Dec 27, 2016 at 22:29
  • do you know why I can't use \src within the itemize environment?
    – Philipp
    Dec 27, 2016 at 22:46
  • \begin{itemize}\item \src{foo} \foo \end{itemize} works for me
    – user31729
    Dec 27, 2016 at 22:51
10

Christian Hupfer has well explained what happens. You might enjoy a different approach based on expl3.

The main function used is \cs_new:cpx, which is a variant of \cs_new:Npn.

  1. cs stands for “control sequence”
  2. new is self explaining
  3. : separates the function name from the signature, that is, the list of its arguments
  4. N stands for a single token
  5. p stands for “parameter text” (in the example case below nothing)
  6. n stands for “braced argument” (the replacement text)

The variant is \cs_new:cpx where c means that we expect a braced argument which will be transformed into a single symbolic token with its backslash at the beginning; x instead means that the corresponding argument will be fully expanded. We need full expansion because we want to store the current value of the counter, not the instructions to produce the value.

The other functions are \int_new:N that allocates a new variable of type int (integer) and \int_gincr:N that globally increments the variable.

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

enter image description here

5
  • Isn't this a little bit over the top ? ;-)
    – user31729
    Dec 27, 2016 at 22:55
  • @ChristianHupfer Why? It's essentially the same as yours, but with no \expandafter trickery. ;-)
    – egreg
    Dec 27, 2016 at 23:23
  • I know, but it might be confusing for somebody not familiar with L3 - syntax.
    – user31729
    Dec 28, 2016 at 8:51
  • Arguably, L3 syntax is an easier lift than dealing with the vagaries of TeX's macro expansion system.
    – Don Hosek
    Nov 9, 2020 at 17:04
  • @DonHosek Really! No more \expandafter! :-)
    – egreg
    Nov 9, 2020 at 17:14
4

As an other option you can use the package etoolbox. The package provides a lot of useful commands and hooks.

In your case the command \csdef is useful which is defined by etoolbox. This is similar to the solution of Christian.

\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}
3
  • Yes, but my solution does not need a package (see the comment of Andrew Swann below my answer ;-) (+1)
    – user31729
    Jan 4, 2017 at 20:26
  • @ChristianHupfer: Sorry. I missed this. (on the other side: too many comments ;-) ) Jan 4, 2017 at 20:33
  • Blame the O.P. :D
    – user31729
    Jan 4, 2017 at 20:36
0

You can use the package zref for making things available throughout the entire document—analogously to LaTeX 2ε's \label-\ref-mechanism.

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

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .