如何在 tcolorbox 中定义标签?

如何在 tcolorbox 中定义标签?

灵感来自这个很好的答案,我尝试使用 排版我的定义tcolorbox。我的文档包含数百个遵循以下模式的定义:

\begin{definition}
% ...
\label{something:meaningful}
\end{definition}

我的问题是,我还没有找到一种方法来definition根据tcolorbox标签的工作位置定义环境。为了演示该问题,我创建了一个 MWE:

\documentclass[12pt]{book}

\usepackage[paperheight=100in]{geometry} % just to allow taking a screen shot...
\usepackage[most]{tcolorbox}

% this is my current "definition" environment
\newtcolorbox[auto counter,number within=chapter]{definition}{
  enhanced,
  breakable,
  fonttitle=\sc,
  title={Definition \thetcbcounter}
}
\let\clearpage\relax % also to allow a screenshot

\begin{document}

\chapter{First Chapter}
\section{Section 1}
\begin{definition}
A first definition. Labeled \texttt{def:A}.
\label{def:A}
\end{definition}

\section{Section 2}
\begin{definition}
Another definition. Labeled \texttt{def:B}.
\label{def:B}
\end{definition}

\subsection{With a Subsection}
\begin{definition}
Another definition -- this time nested. Labeled \texttt{def:C}.
\label{def:C}
\end{definition}

\chapter{Second Chapter}
\begin{definition}
Definition in the second chapter. Labeled \texttt{def:D}.
\label{def:D}
\end{definition}

Judging from the definition headers, it looks like the per-chapter-counter seems to work.
But lets see what happens if we reference the definitions.
\begin{itemize}
  \item \texttt{\textbackslash ref\{def:A\}} refers to Definition \ref{def:A}.
  \item \texttt{\textbackslash ref\{def:B\}} refers to Definition \ref{def:B}.
  \item \texttt{\textbackslash ref\{def:C\}} refers to Definition \ref{def:C}.
  \item \texttt{\textbackslash ref\{def:D\}} refers to Definition \ref{def:D}.
\end{itemize}


\end{document}

因此,我使用基于每个章节的自动计数器。这个计数器本身似乎也能工作,因为我的定义标题具有正确的每个章节编号。问题是引用标签不会给出相同的数字。这是上述 MWE 的输出:

输出

事实上,标签看起来只是引用周围的章节/部分。有没有办法让标签与定义编号保持一致?

我发现,label对于由 定义的环境,有一个可选参数newtcolorbox。但是,我还没有找到在我的案例中使用它的方法。我猜它只适用于具有强制参数的环境,并且我不想破坏与遵循上述模式的所有现有定义的兼容性。

答案1

使用label以下键tcolorbox

\documentclass[12pt]{book}
\usepackage[most]{tcolorbox}

% this is my current "definition" environment
\newtcolorbox[auto counter,number within=chapter]{definition}[1][]{
  enhanced,
  breakable,
  fonttitle=\scshape,
  title={Definition \thetcbcounter},
  #1
}

\begin{document}

\chapter{First Chapter}
\section{Section 1}
\begin{definition}[label=def:A]
A first definition. Labeled \texttt{def:A}.
\end{definition}

\section{Section 2}
\begin{definition}[label=def:B]
Another definition. Labeled \texttt{def:B}.
\end{definition}

\subsection{Whit a Subsection}
\begin{definition}[label=def:C]
Another definition -- this time nested. Labeled \texttt{def:C}.
\end{definition}

\chapter{Second Section}
\begin{definition}[label=def:D]
Definition in the second chapter. Labeled \texttt{def:D}.
\end{definition}

Judging from the definition headers, it looks like the per-chapter-counter seems to work.
But lets see what happens if we reference the definitions.
\begin{itemize}
  \item \texttt{\textbackslash ref\{def:A\}} refers to Definition \ref{def:A}.
  \item \texttt{\textbackslash ref\{def:B\}} refers to Definition \ref{def:B}.
  \item \texttt{\textbackslash ref\{def:C\}} refers to Definition \ref{def:C}.
  \item \texttt{\textbackslash ref\{def:D\}} refers to Definition \ref{def:D}.
\end{itemize}


\end{document}

在此处输入图片描述

在我的例子中,我使用了

\newtcolorbox[auto counter,number within=chapter]{definition}[1][]{
  enhanced,
  breakable,
  fonttitle=\scshape,
  title={Definition \thetcbcounter},
  #1
}

因此标签必须作为可选参数传递:

\begin{definition}[label=<text>]
...
\end{definition}

但你也可以说

\newtcolorbox[auto counter,number within=chapter]{definition}[1][]{
  enhanced,
  breakable,
  fonttitle=\scshape,
  title={Definition \thetcbcounter},
  label=#1
}

然后简单地

\begin{definition}[<text>]
...
\end{definition}

或者你可以将此作为强制性论点。

评论

theorems来自的库允许tcolorbox使用

\newtcbtheorem[<init options>]{<name>}{<display name>}{<options>}{<prefix>}

进而

\begin{name}{}{<label>}
...
\end{name}

因此可以说\ref{<prefix:<label>}获得交叉引用。我没有在问题链接的答案中使用这个,因为不需要编号(因此不需要交叉引用)。

答案2

\label这是一种在内部进行工作的方法tcolorbox– 但这是真的很脏并且仅在假设该\label命令紧随该\begin{definition}命令的情况下才有效!

\label它通过使用xparses参数“捕获”令牌来工作t。要使用,xparse我们必须手动创建环境,而不是通过库theorem

这种丑陋的黑客手段的一个优点是,一些 tex(t) 编辑器的自动完成功能应该能够找到以这种方式定义的标签,而用 创建的标签[label=def:test]将无法找到 - 至少是“开箱即用”的。

考虑以下 MWE:

\documentclass{article}
\usepackage{cleveref}
\usepackage{tcolorbox}
\tcbuselibrary{xparse,skins,breakable}

\tcbset{%
    basestyle/.style={enhanced,breakable,
        fonttitle=\scshape,
        coltitle=white},
    defstyle/.style={basestyle,colback=red!10!white},
    theostyle/.style={basestyle,colback=blue!10!white},
}
\DeclareTColorBox[auto counter,number within=section,crefname={definition}{definitions}]{definition}{ o O{} t\label g }{%
    defstyle,IfValueTF={#1}{title={Definition~\thetcbcounter\ (#1)}}{title=Definition~\thetcbcounter}, IfBooleanTF={#3}{label=#4}{},#2}

\begin{document}

\begin{definition}[My title]\label{def:test}
    Foo.
\end{definition}

This was \cref{def:test}.
Unlabeled definition:

\begin{definition}[Cool Title][colback=orange!10!white]
    Just a test.
\end{definition}

\end{document}

输出: 在此处输入图片描述

答案3

请考虑使用@Gonzola 的答案,因为这是适当的方法。提供良好常用表达功能应该允许您以单一的“搜索和替换”方式修补您的文档。

我试图使用包文档中描述的number freestyle选项\newtcolorbox,但是这似乎也不起作用,所以我猜测tcolorbox包中有一个错误(如何定义引用?)......但这纯粹是推测。

尽管如此,这里有一个糟糕的解决方案,但它确实有效。要将其应用于当前文档,您只需搜索每次出现\label{def:代替它与\addtocounter{definition}{-1}\refstepcounter{definition}\label{def:

\label使用此代码,无论您是否定义标签,标签都将保持一致每一个定义。

代码:

\documentclass[12pt]{book}

\usepackage[paperheight=100in]{geometry} % just to allow taking a screen shot...
\usepackage[most]{tcolorbox}

%% Create a new counter that will follow tcolorbox's numbering
\newcounter{definition}[chapter]
\renewcommand*{\thedefinition}{\noexpand\thechapter.\noexpand\arabic{definition}}

% this is my current "definition" environment
\newtcolorbox[auto counter,number within=chapter]{definition}{
  enhanced,
  breakable,
  fonttitle=\sc,
  title={Definition \thetcbcounter\refstepcounter{definition}}
}
\let\clearpage\relax % also to allow a screenshot

\begin{document}

\chapter{First Chapter}
\section{Section 1}
\begin{definition}
A first definition. Labeled \texttt{def:A}.
\addtocounter{definition}{-1}\refstepcounter{definition}\label{def:A}
\end{definition}

\section{Section 2}
\begin{definition}
Another definition. Labeled \texttt{def:B}.
\addtocounter{definition}{-1}\refstepcounter{definition}\label{def:B}
\end{definition}

\subsection{Definition without label}
\begin{definition}
Another definition -- this time without label.
\end{definition}

\subsection{Whit a Subsection}
\begin{definition}
Another definition -- this time nested. Labeled \texttt{def:C}.
\addtocounter{definition}{-1}\refstepcounter{definition}\label{def:C}
\end{definition}

\chapter{Second Chapter}
\begin{definition}
Definition in the second chapter. Labeled \texttt{def:D}.
\addtocounter{definition}{-1}\refstepcounter{definition}\label{def:D}
\end{definition}

Judging from the definition headers, it looks like the per-chapter-counter seems to work.
But lets see what happens if we reference the definitions.
\begin{itemize}
  \item \texttt{\textbackslash ref\{def:A\}} refers to Definition \ref{def:A}.
  \item \texttt{\textbackslash ref\{def:B\}} refers to Definition \ref{def:B}.
  \item \texttt{\textbackslash ref\{def:C\}} refers to Definition \ref{def:C}.
  \item \texttt{\textbackslash ref\{def:D\}} refers to Definition \ref{def:D}.
\end{itemize}


\end{document}

输出:

上述代码的输出

答案4

⟨name⟩这似乎可行。其思路是,如果您已使用定义了环境\newtcbtheorem[⟨init options⟩]{⟨name⟩}{⟨display name⟩}{⟨options⟩}{⟨prefix⟩},例如\newtcbtheorem[number within=section]{definitiontcb}{Definition}{}{def},则可以使用\newtcbtheoremautolabelaux[⟨name2⟩]{⟨name⟩}{⟨prefix⟩},例如\newtcbtheoremautolabelaux[definitiontcbautolabel]{definitiontcb}{def},获取一个新环境⟨name2⟩,该环境在其主体中抓取标签并将其作为 的参数⟨name⟩,即\begin{⟨name2⟩}{#1}...\label{⟨label⟩}...\end{⟨name2⟩}等同于\begin{⟨name⟩}{#1}{⟨label⟩}......\end{⟨name⟩}

如果您从来不需要直接使用 tcb 环境,而总是想要自动标记变体,那么您可以简单地重命名\newtcbtheorem\newtcbtheoremautolabel:该命令\newtcbtheoremautolabel[⟨init options⟩][⟨name⟩]{⟨name2⟩}{⟨display name⟩}{⟨options⟩}{⟨prefix⟩}具有与相同的接口\newtcbtheorem(带有一个额外的可选参数,用于中间 tcb 环境的名称)。

\documentclass{book}
\usepackage{proof-at-the-end}
\usepackage[most]{tcolorbox}
\usepackage{etoolbox}
\usepackage{stix}
\usepackage{xparse}


\ExplSyntaxOn

% \gobble:n just discards its argument
\cs_new:Npn \gobble:n #1 {}

\cs_generate_variant:Nn \tl_if_blank_p:n {V}
\tl_new:N\tl_head
\tl_new:N\tl_tail
\tl_new:N\tl_beforetail
\tl_const:Nn \tl_just_label {\label}

% \extract_label:NN \tl_body \tl_label
% removes \label{⟨label⟩} from \tl_body and stores ⟨label⟩ in \tl_label
\cs_new:Npn \extract_label:NN #1 #2 {
  \tl_if_in:NnTF #1 {\label} {% Some \label: replace it by gobble:n in #1 and store its argument in #2
    \tl_set_eq:NN\tl_tail#1
    \bool_do_until:nn{% Search for the \label token
      \tl_if_eq_p:NN\tl_head\tl_just_label% || \tl_if_blank_p:V\tl_tail
    }{
      \tl_set:Nx\tl_head{\tl_head:N\tl_tail}
      \tl_set:Nx\tl_tail{\tl_tail:N\tl_tail}
    }
    % At this point, tl_head is \label, and tl_tail is whatever is after it
    \tl_set:Nx\tl_head{\tl_head:N\tl_tail}
    % At this point, tl_head is the (potential) argument of \label
    \tl_if_blank:VTF\tl_tail{
      \ERROR
    } {
      \tl_set_eq:NN #2 \tl_head
      \tl_replace_once:Nnn #1 {\label} {\gobble:n}
    }
  } {% No \label: leave #1 as is and make #2 empty
    \tl_clear:N #2
  }
}

\exp_args_generate:n {Nnnf}
\tl_new:N\tl_body
\tl_new:N\tl_label

% After calling
% \newtcbtheorem[⟨init options⟩]{⟨name⟩}{⟨display name⟩}{⟨options⟩}{⟨prefix⟩}
% and
% \newtcbtheoremautolabelaux[⟨name2⟩]{⟨name⟩}{⟨prefix⟩}
% the environment ⟨name2⟩ is defined such that \begin{⟨name2⟩}{#1}...\label{⟨label⟩}...\end{⟨name2⟩}
% behaves like
% \begin{⟨name⟩}{#1}{⟨label⟩}......\end{⟨name⟩}
% By default, ⟨name2⟩ = ⟨name⟩autolabel
\NewDocumentCommand{\newtcbtheoremautolabelaux}{omm}{
  \NewDocumentEnvironment{\IfNoValueTF{#1}{#2autolabel}{#1}}{mb}{% ##1 = title, ##2 = body
    % decompose the body ##2 into the label \tl_label and the rest tl_body
    \tl_set:Nn\tl_body{##2}%
    \extract_label:NN\tl_body\tl_label
    % remove the prefix #3 from \tl_label
    \tl_set:Nx\tl_label{\tl_range:Nnn \tl_label { \tl_count:n{#3} + 2 } { -1 }}
    % Call the #2 environment with the expected arguments
    \exp_args:NnnV\begin{#2}{##1}\tl_label
      \tl_use:N\tl_body%
    \end{#2}%
  }{}
}

% \newtcbtheoremautolabel[⟨init options⟩][⟨name⟩]{⟨name2⟩}{⟨display name⟩}{⟨options⟩}{⟨prefix⟩}
% is just
% \newtcbtheorem[⟨init options⟩]{⟨name⟩}{⟨display name⟩}{⟨options⟩}{⟨prefix⟩}
% followed by
% \newtcbtheoremautolabelaux[⟨name2⟩]{⟨name⟩}{⟨prefix⟩}
% with ⟨name⟩ = ⟨name2⟩auxnoautolabel by default
\NewDocumentCommand{\newtcbtheoremautolabel}{O{}ommmm}{
  \IfNoValueTF{#2}{
    \newtcbtheorem[#1]{#3auxnoautolabel}{#4}{#5}{#6}
    \newtcbtheoremautolabelaux[#3]{#3auxnoautolabel}{#6}
  }{
    \newtcbtheorem[#1]{#2}{#4}{#5}{#6}
    \newtcbtheoremautolabelaux[#3]{#2}{#6}
  }
}

\ExplSyntaxOff

\newtcbtheorem[number within=section]{definitiontcb}{Definition}{}{def}
\newtcbtheoremautolabelaux[definitiontcbautolabel]{definitiontcb}{def}

% Or both combined:
%\newtcbtheoremautolabel[number within=section]{definitiontcbautolabel}{Definition}{}{def}

% Since the title is an optional argument for amsthm, I prefer using a definition that matches that
% (I switched from using \NewEnviron to \NewDocumentEnvironment in \newtcbtheoremautolabelaux because otherwise this did not work)
\newenvironment{definition}[1][]{%
  \begin{definitiontcbautolabel}{#1}%
}{%
  \end{definitiontcbautolabel}%
}%


\begin{document}

\chapter{First Chapter}
\section{Section 1}

\begin{definition}
A first definition. Labeled \texttt{def:A}.
\label{def:A}
\end{definition}

\section{Section 2}
\begin{definition}
Another definition. Labeled \texttt{def:B}.
\label{def:B}
\end{definition}

\subsection{With a Subsection}
\begin{definition}
Another definition -- this time nested. Labeled \texttt{def:C}.
\label{def:C}
\end{definition}

\chapter{Second Chapter}
\begin{definition}
Definition in the second chapter. Labeled \texttt{def:D}.
\label{def:D}
\end{definition}

\begin{definition}
Definition in the second chapter. Labeled \texttt{def:E}.
\label{def:E}
\end{definition}

Judging from the definition headers, it looks like the per-chapter-counter seems to work.
But lets see what happens if we reference the definitions.
\begin{itemize}
  \item \texttt{\textbackslash ref\{def:A\}} refers to Definition \ref{def:A}.
  \item \texttt{\textbackslash ref\{def:B\}} refers to Definition \ref{def:B}.
  \item \texttt{\textbackslash ref\{def:C\}} refers to Definition \ref{def:C}.
  \item \texttt{\textbackslash ref\{def:D\}} refers to Definition \ref{def:D}.
  \item \texttt{\textbackslash ref\{def:E\}} refers to Definition \ref{def:E}.
\end{itemize}

\end{document}

相关内容