我使用自定义命令制作了一个自定义计数器,该命令可步进计数器并为其设置自动标签。但是,当从标题调用它并使用该caption
包时,我的计数器会步进两次。这是一个 MWE:
\documentclass{book}
\usepackage{caption}
\newcounter{example}[chapter]
\renewcommand{\theexample}{\thechapter{}.\arabic{example}}
\providecommand{\example}[1]{\refstepcounter{example}\label{ex:#1}{\theexample}}
\begin{document}
\begin{figure}[h!]
\caption{\protect\example{my_example}}
\end{figure}
\end{document}
如果我注释掉该行\usepackage{caption}
,我就会得到正确的结果。
这是一个错误吗?或者我在这里犯了一些非常基本的错误?
答案1
您也可以在没有 caption 包的情况下进行双重评估(取决于文本的长度)。该caption
包提供了一种确保文本仅被评估一次的方法:
\usepackage[singlelinecheck=false]{caption}
答案2
正如 David 所说,字幕文本通常会被评估一次或两次,具体取决于字幕文本的长度。(因此,如果您的字幕文本长度超过一行,即使没有caption
软件包,您也会遇到同样的问题。)
为了使事情更加一致,该caption
包总是对标题文本进行两次评估。
使用caption
带有选项的包singlelinecheck=false
(按照 David 的建议)将关闭第一次评估,但它也会关闭包的单行功能caption
,为您提供左对齐(而不是居中)的短标题。
如果这对您来说没问题,这是解决问题的最简单方法。但如果您想保留单行功能,我们必须查看包的内部结构caption
:
在第一次评估期间(确定标题文本的长度)\caption@prepareslc
将会被使用,因此可以通过扩展这个宏来摆脱双重评估的副作用。
一个例子:
\documentclass{book}
\usepackage{caption}
\newcounter{example}[chapter]
\renewcommand{\theexample}{\thechapter{}.\arabic{example}}
\newcommand{\stepexample}{\refstepcounter{example}}
\DeclareRobustCommand{\example}[1]{\stepexample\label{ex:#1}{\theexample}}
\makeatletter
\g@addto@macro\caption@prepareslc{%
\renewcommand{\stepexample}{\caption@l@stepcounter{example}}}
\makeatother
\begin{document}
\begin{figure}[h!]
\caption{\example{my_example}}
\end{figure}
\ref{ex:my_example}
\end{document}
我在这里做了什么:
example
我已经将计数器的增量外包,\stepexample
以便以后可以重新定义它。- 我已经进行了扩展
\caption@prepareslc
,因此example
计数器只会在评估字幕文本长度时本地递增。(完全不递增它似乎也是一个可行的解决方案,但这会导致字幕文本长度的测量不正确,因为其长度与等等1
不同。)2
- 我使用内部宏
\caption@l@stepcounter
来局部增加example
计数器。
但是为什么我们不重新定义\refstepcounter
到\caption@l@stepcounter
内\caption@prepareslc
?事实上,一些软件包版本已经这样做了,因为这似乎是所有计数器的简单全局解决方案,但我不得不放弃这个解决方案,因为一些代码(由其他软件包提供)对 到 的补丁根本caption
不满意。\refstepcounter