8

I'd like to be able to number arbitrary objects (in my case, chemical compounds) within a document. Ideally this would involve a command a bit like \ref, but where you don't need a \label. The label would be created, and counter incremented, the first time \ref is called for a particular marker name, subsequent calls return the appropriate number.

The reason for this is that there's no specific "definition", just that they should be numbered in order of first appearance within the text.

\cref{one} -> 1
\cref{two} -> 2
...
\cref{one} -> 1

I think the way to do this is as following (disclaimer: I haven't ever made new command before!)

\newcounter{cref}
\newcommand{\cref}[1]{
   IF MARKER #1 DOESN'T EXIST:
      \refstepcounter{cref}\thecref\label{#1}
   \ref{#1}
}

Questions:

  1. Has this been done before? I can't find a package...
  2. Is this a sensible way to do it?
  3. Is it possible to check whether a particular marker hasn't been defined yet?
1
  • 1
    We'd like to keep answers separate from questions, so you should write a separate answer instead of editing your answer into the question. Self-answers are perfectly admissibe, and a well-written answer may earn you additional reputation.
    – lockstep
    Jun 5, 2011 at 12:30

4 Answers 4

8
\newcounter{chrefcnt}
\newcommand{\chref}[1]{%
  \ifcsname chref@#1\endcsname
    % do nothing, the command is already defined
  \else
    \stepcounter{chrefcnt}%
    \expandafter\xdef\csname chref@#1\endcsname{\thechrefcnt}%
  \fi
  % now print the number
  \csname chref@#1\endcsname}

With \chref{one} \chref{two} \chref{one} you would get the output 1 2 1.

It's better to use prefixes, so as not to conflict with existing macros, I've used chref@. Some more checks might be needed. There's no need to use the \label-\ref system, in this case. We simply define the command corresponding to the label to expand to the assigned number.

(Thanks to lockstep for having pointed out a name conflict.)

New implementation

Following the suggestion by Richard, here is a new implementation with an optional argument for "subcoumpounds"

\documentclass{article}
\makeatletter
\newcounter{chref@cnt}
\def\chrefstyle{\textbf}
\newcommand{\chref}[2][]{%
  \ifcsname chref@#2\endcsname
    % do nothing, the compound is already defined
  \else
    \stepcounter{chref@cnt}%
    \expandafter\xdef\csname chref@#2\endcsname{\arabic{chref@cnt}}%
    \expandafter\gdef\csname chrefsub@#2\endcsname{0}%
  \fi  
  % now print the number
  \chrefstyle{\csname chref@#2\endcsname}%
  \if\relax\detokenize{#1}\relax
    % do nothing, there's no optional argument
  \else
    \ifcsname chref@#2@#1\endcsname
      % do nothing, the subcompound is already defined
    \else
      \@tempcnta=\csname chrefsub@#2\endcsname
      \advance\@tempcnta\@ne
      \expandafter\xdef\csname chref@#2@#1\endcsname{\@alph\@tempcnta}%
      \expandafter\xdef\csname chrefsub@#2\endcsname{\number\@tempcnta}%
    \fi
    % now print the letter
    \chrefstyle{\csname chref@#2@#1\endcsname}
  \fi}
\makeatother

\begin{document}

\chref[X]{one} $\to$ 1a

\chref[Y]{one} $\to$ 1b

\chref{two} $\to$ 2

\chref[Z]{one} $\to$ 1c

\chref{one} $\to$ 1

\chref[A]{two} $\to$ 2a

\end{document}

For each main compound we remember the number of subcompounds already defined, initializing it to 0; for \chref{one} we define \chrefsub@one to be 0. If a subcompound is requested and not yet defined, we set to the remembered number so far of subcompounds the temporary count register \@tempcnta and advance it by one. We define the corresponding control sequence (for \chref[X]{one} it would be \chref@one@X) to expand to the alphabetic representation of the value of \@tempcnta and remember the value of the "subcompounds-so-far".

2
  • 2
    Note: @cref is used as a prefix by the cleveref package (and \cref as well as its most important command name).
    – lockstep
    Jun 4, 2011 at 18:18
  • Great, thanks! I can double this up to allow sub-compounds as well - see edited question. What would be really cool is \chref[A,B,C,F]{one} -> 1a-c,f but I expect that's not so trivial ;-) Jun 5, 2011 at 12:03
3

Have you looked at the chemcompounds package? The \compound macro seems to cover pretty much what you want.

1
  • I hadn't seen that one, no - thanks for pointing it out! (Also see my comment on the previous answer + edited question). Jun 5, 2011 at 12:12
1

Starting from egreg's answer, I've come up with the following:

\makeatletter
\newcounter{chref@cnt}
\def\chrefstyle{\textbf}
\newcommand{\chref}[2][]{%
  \ifcsname chref@#2\endcsname
    % do nothing, the compound is already defined
  \else
    \stepcounter{chref@cnt}%
    \expandafter\xdef\csname chref@#2\endcsname{\arabic{chref@cnt}}%
    \newcounter{chref@#2@cnt}%
  \fi  
  % now print the number
  \chrefstyle{\csname chref@#2\endcsname}%
  \ifthenelse{\equal{#1}{}}{}{%
    \ifcsname chref@#2@#1\endcsname
      % do nothing, the subcompound is already defined
    \else
      \stepcounter{chref@#2@cnt}%
      \expandafter\xdef\csname chref@#2@#1\endcsname{\alph{chref@#2@cnt}}%
    \fi
    % now print the letter
    \chrefstyle{\csname chref@#2@#1\endcsname}}}
\makeatother

Then:

\chref[X]{one} -> 1a
\chref[Y]{one} -> 1b
\chref[X]{one} -> 1a
\chref{one}    -> 1
4
  • I've moved the second \newcounter outside the definition; it's sufficient to have a second counter linked to the first one so that an increment to the first counter will reset to zero the second one.
    – egreg
    Jun 5, 2011 at 17:50
  • @egreg would that still work if you have 1a, 1b, 2a, 1c, etc? i.e. you may need to increment the counter for 1 after you've started the counter for 2. Jun 5, 2011 at 20:00
  • No, it wouldn't work with that sequence. In that case a quite different approach is needed, but defining a new counter for each \chref with optional argument is out of the question.
    – egreg
    Jun 5, 2011 at 20:17
  • See the new implementation; I've reverted your answer to the original one (but it should be remarked that defining new counters in such a definition is bad programming style, as it wastes resources).
    – egreg
    Jun 5, 2011 at 20:46
1

To answer your first question

Has this been done before? I can't find a package...

There actually are several packages for the numbering of chemical compounds, besides the one Joseph already mentioned (second in the list below):

  1. chemnum \cmpd{main.sub} => 1a
  2. chemcompounds \declarecompound[1a]{label}\compound{label} => 1a
  3. bpchem \CNlabelsub{main}{sub} => 1a
  4. chemcono (I cannot recommend this one in good conscience :( )
2
  • chemnum looks like it would save an awful lot of effort! Thanks for the suggestion! Mar 22, 2012 at 21:15
  • @Richard Glad if I could help :)
    – cgnieder
    Mar 22, 2012 at 23:58

You must log in to answer this question.

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