![如何在 tcolorbox 中定义标签?](https://linux22.com/image/306809/%E5%A6%82%E4%BD%95%E5%9C%A8%20tcolorbox%20%E4%B8%AD%E5%AE%9A%E4%B9%89%E6%A0%87%E7%AD%BE%EF%BC%9F.png)
灵感来自这个很好的答案,我尝试使用 排版我的定义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
它通过使用xparse
s参数“捕获”令牌来工作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}