Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have a custom macro, \somemacro{}{}. In the macro, #1 is set to a unique key (e.g. 11) and #2 contains other data. This macro appears throughout my document:

    This is some text. \somemacro{11}{This is information about animals.}
    \somemacro{15}{This is information about trees.} Here is some other text.
\chapter{Here is a new chapter}
    \somemacro{17}{This is information about the sky.}
    \somemacro{01}{This is information about space.}

Occasionally, I need to cross-reference the appearance of the macros, by referring to the key number. This is similar to \ref or \pageref, but the value will be a number referring to the order of appearance of that key. E.g. In the above, #15 appears second, so \whereiskey{15} would return 2. #01 appears fourth in the document, so \whereiskey{01} would return 4.

To do this, I have created a counter labelcounter, which is incremented each time the macro is used. To create a variable that has a key and a value, I tried to create use a counter (as it is the only variable I know that has a name and a value), named for the value of the key:

\documentclass{article}
\newcounter{labelcounter}
\setcounter{labelcounter}{0}
\newcommand{\somemacro}[2]{
    \stepcounter{labelcounter}
    \newcounter{#1}
    \setcounter{labelcounter}
    #2
}
\newcommand{\whereiskey}[1]{
    \arabic{#1}
}
\begin{document}
    \somemacro{08}{This is some text.}
    \somemacro{12}{This is some other text.}
    \somemacro{10}{This is some more text.}
    This number should say when \#12 appears: \whereiskey{10}.
\end{document}

This does not seem to work. When I try to compile, it reports,

Missing number, treated as zero. \somemacro{08}{This is some text.}.
  • How can I get this to work?
  • Is there a better approach?
share|improve this question

1 Answer 1

up vote 4 down vote accepted

You're not specifying to what value the counter labelcounter should be set to.

However, defining a new counter for every instance of \somemacro is definitely a bad idea. Besides, \arabic{#1} will always return 0.

If keys are unique, you should refer to those.

\newcounter{keycounter}
\makeatletter
\newcommand{\somemacro}[2]{%
  \@ifundefined{keyappeared@#1}
    {\stepcounter{keycounter}%
     \expandafter\xdef\csname keyappeared@#1\endcsname{\the\c@keycounter}%
    }{}%
  #2}
\newcommand{\whereiskey}[1]{%
  \@ifundefined{keyappeared@#1}
    {``wrong or not yet appeared key''}
    {\@nameuse{keyappeared@#1}}}
\makeatother

Now with your input

\somemacro{08}{This is some text.}
\somemacro{12}{This is some other text.}
\somemacro{10}{This is some more text.}
This number should say when \#10 appears: \whereiskey{10}.

you'll get 3 from \whereiskey{10}. If the same key appears twice, it won't increment keycounter.

You can also use directly the \label-\ref system:

\newcounter{keycounter}
\makeatletter
\newcommand{\somemacro}[2]{%
  \@ifundefined{keyappeared@#1}
    {\refstepcounter{keycounter}\label{keyappeared@#1}%
     \global\expandafter\let\csname keyappeared@#1\endcsname\@empty
    }{}%
  #2}
\newcommand{\whereiskey}[1]{%
  \@ifundefined{keyappeared@#1}
    {\typeout{Possibly wrong key, run LaTeX again}}{}%
    \ref{keyappeared@#1}%
  }
\makeatother

This frees you from the constraint that a \whereiskey command must appear after the corresponding \somemacro.

share|improve this answer
    
The revised method is a good idea, but I can't get the it to work after repeated compiles. Yields a blank for keys that appear after the are referenced. –  Peter Grill Jan 27 '12 at 16:22
    
@PeterGrill Thanks: misplaced braces! –  egreg Jan 27 '12 at 16:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.