我希望能够对文档中的任意对象(在我的情况下是化合物)进行编号。理想情况下,这将涉及一个有点像 \ref 的命令,但您不需要 \label。第一次为特定标记名称调用 \ref 时,将创建标签并增加计数器,后续调用将返回相应的数字。
原因是没有具体的“定义”,只是应该按照它们在文本中首次出现的顺序进行编号。
\cref{one} -> 1
\cref{two} -> 2
...
\cref{one} -> 1
我认为这样做的方法如下(免责声明:我以前从未发出过新命令!)
\newcounter{cref}
\newcommand{\cref}[1]{
IF MARKER #1 DOESN'T EXIST:
\refstepcounter{cref}\thecref\label{#1}
\ref{#1}
}
问题:
- 以前有人做过这个吗?我找不到包裹……
- 这是一个明智的做法吗?
- 是否可以检查特定标记是否尚未定义?
答案1
\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}
你\chref{one} \chref{two} \chref{one}
将得到输出 1 2 1。
最好使用前缀,以免与现有宏冲突,我使用了chref@
。可能需要更多检查。在这种情况下,无需使用\label
-\ref
系统。我们只需定义与标签相对应的命令以扩展到指定的数字。
(感谢 lockstep 指出名称冲突。)
新实施
根据 Richard 的建议,这里有一个新的实现,其中包含一个可选的“子化合物”参数
\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}
对于每个主化合物,我们记住已定义的子化合物的数量,将其初始化为 0;对于\chref{one}
我们定义\chrefsub@one
为0
。如果请求子化合物但尚未定义,我们将临时计数寄存器设置为迄今为止记住的子化合物数量,\@tempcnta
并将其加一。我们定义相应的控制序列(因为\chref[X]{one}
它将是\chref@one@X
)以扩展为 值的字母表示\@tempcnta
并记住“迄今为止的子化合物”的值。
答案2
你看过chemcompounds
包?这个\compound
宏似乎几乎涵盖了你想要的一切。
答案3
从 egreg 的回答开始,我得出了以下结论:
\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
然后:
\chref[X]{one} -> 1a
\chref[Y]{one} -> 1b
\chref[X]{one} -> 1a
\chref{one} -> 1
答案4
回答你的第一个问题
以前有人做过这个吗?我找不到包裹……
除了 Joseph 已经提到的包(下面列表中的第二个)之外,实际上还有几个用于对化合物进行编号的包:
chemnum
\cmpd{main.sub}
=>1achemcompounds
\declarecompound[1a]{label}\compound{label}
=>1abpchem
\CNlabelsub{main}{sub}
=>1achemcono
(我不能凭良心推荐这个:()