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'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?
share|improve this question
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 '11 at 12:30

4 Answers 4

up vote 8 down vote accepted
\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".

share|improve this answer
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 '11 at 18:18
    
@caramdir: thanks for your eagle eye. –  egreg Jun 4 '11 at 19:52
    
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 ;-) –  Richard Ingham Jun 5 '11 at 12:03

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 :( )
share|improve this answer
    
chemnum looks like it would save an awful lot of effort! Thanks for the suggestion! –  Richard Ingham Mar 22 '12 at 21:15
    
@Richard Glad if I could help :) –  cgnieder Mar 22 '12 at 23:58

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
share|improve this answer
    
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 '11 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. –  Richard Ingham Jun 5 '11 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 '11 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 '11 at 20:46

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

share|improve this answer
    
I hadn't seen that one, no - thanks for pointing it out! (Also see my comment on the previous answer + edited question). –  Richard Ingham Jun 5 '11 at 12:12

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.