使用 caption 包从 caption 调用时,自定义计数器会执行两次

使用 caption 包从 caption 调用时,自定义计数器会执行两次

我使用自定义命令制作了一个自定义计数器,该命令可步进计数器并为其设置自动标签。但是,当从标题调用它并使用该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

相关内容