考虑以下 MWE
\documentclass{article}
\usepackage{amsthm}
\usepackage{thmtools}
\usepackage[nameinlink]{cleveref}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{ \IfEmptyTF }{ m m m }
{
\sbox0{#1}
\ifdim\wd0=0pt
#2
\else
#3
\fi
}
\ExplSyntaxOff
\makeatletter
\declaretheoremstyle[
postheadspace=.5em,
headpunct={},
notebraces={}{},
notefont=\bfseries,
headformat=\IfEmptyTF{\NOTE}{\NAME~\NUMBER}{\let\thmt@space\@empty\NOTE}
]{theorem}
\makeatother
\declaretheorem[
style=theorem,
name=Theorem
]{theorem}
\crefname{theorem}{Theorem}{Theorems}
\begin{document}
\begin{theorem}[label=thm:a]
A theorem.
\end{theorem}
\begin{theorem}[name=Important theorem, label=thm:b]
Another theorem.
\end{theorem}
\cref{thm:a} and \cref{thm:b} % <-- should be 'Theorem 1 and Important theorem'
\end{document}
产生
我想修改\crefname{theorem}{..}{..}
这样的内容:如果第 n 个定理没有名称,则\cref{..}
打印该内容;如果有名称,则仅打印该名称。Theorem n
我知道这可能可以通过\nameref
或来完成\autoref
,但\cref
唯一的解决方案是否可行?
答案1
我不确定这是否可以使用cleveref
机器来实现,因为\crefformat
似乎无法访问标签。此外,cleveref
设计为能够组合多个编号项目而不重复项目类型(例如“定理 1、3 和 10”),这与您想要做的事情不太吻合(需要添加文章...)。
话虽如此,我们可以重新定义\cref
为:
检测参数是否仅由一个标签组成;
如果是这种情况,并且它具有由包记录的名称,则检索该名称并打印它(我为此
nameref
使用了 great包);refcount
否则,让正常
\cref
命令处理该情况。
无关:你的维度测试\IfEmptyTF
有点奇怪。我以更好的方式重新实现了它,1但你可能更想测试第一个参数的第一级扩展是否\IfEmptyTF
为空。这很容易做到,但我保留了“装箱+维度测试”的原则,以防这对你的实际文档很重要。
\documentclass{article}
\usepackage{letltxmacro}
\usepackage{nameref}
\usepackage{refcount}
\usepackage{amsthm}
\usepackage{thmtools}
\usepackage[nameinlink]{cleveref}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand { \IfEmptyTF } { m }
{
\hbox_set:Nw \l_tmpa_box #1 \hbox_set_end:
\dim_compare:nNnTF { \box_wd:N \l_tmpa_box } = { \c_zero_dim }
% The T and F clauses are taken from what follows in the input stream
}
% Save the original \cref commmand
\LetLtxMacro{\__noibe_orig_cref:n}{\cref}
\tl_new:N \l__noibe_theorem_name_tl
\RenewDocumentCommand{ \cref }{ m }
{
\int_compare:nNnTF { \clist_count:n {#1} } > { 1 }
{ \__noibe_orig_cref:n {#1} }
{
\exp_args:NNo \tl_set:No \l__noibe_theorem_name_tl
{ \getrefbykeydefault {#1} { name } { } }
\tl_if_empty:NTF \l__noibe_theorem_name_tl
{ \__noibe_orig_cref:n {#1} }
{ \l__noibe_theorem_name_tl }
}
}
\ExplSyntaxOff
\makeatletter
\declaretheoremstyle[
postheadspace=.5em,
headpunct={},
notebraces={}{},
notefont=\bfseries,
headformat=\IfEmptyTF{\NOTE}{\NAME~\NUMBER}{\let\thmt@space\@empty\NOTE}
]{theorem}
\makeatother
\declaretheorem[
style=theorem,
name=Theorem
]{theorem}
\crefname{theorem}{Theorem}{Theorems}
\begin{document}
\begin{theorem}[label=thm:a]
A theorem.
\end{theorem}
\begin{theorem}[name=Important theorem, label=thm:b]
Another theorem.
\end{theorem}
\cref{thm:a} and \cref{thm:b} % “Theorem 1 and Important theorem”
\cref{thm:a,thm:b} % “Theorems 1 and 2”
\end{document}
有问题的例子\IfEmptyTF
这是一个简单的例子,其中我的实现\IfEmptyTF
工作正常而您的实现却产生了错误:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{ \YourIfEmptyTF }{ m m m }
{
\sbox0{#1}
\ifdim\wd0=0pt
#2
\else
#3
\fi
}
\NewDocumentCommand { \MyIfEmptyTF } { m }
{
\hbox_set:Nw \l_tmpa_box #1 \hbox_set_end:
\dim_compare:nNnTF { \box_wd:N \l_tmpa_box } = { \c_zero_dim }
}
\ExplSyntaxOff
\begin{document}
%\YourIfEmptyTF{}{\textbf}{\textit}{foo bar} % Error: Too many }'s.
\MyIfEmptyTF{}{\textbf}{\textit}{foo bar} % 'foo bar' is typeset in bold
\MyIfEmptyTF{non-empty}{\textbf}{\textit}{foo bar} % 'foo bar' is typeset in italics
\end{document}
脚注
- 在读取第二个⟨dimen⟩时,没有扩大开始的风险
#2
,更重要的是,允许每一个电视和F\IfEmptyTF{...}{T}{F}
子句对输入流中跟在 后面的标记进行操作(在您的代码中,在输入流中#2
跟在后面,并且跟在 后面,当您想要实现某些事情时,这可能会成为一大障碍——这在下有说明\else
#3
\fi
有问题的例子\IfEmptyTF
在这个答案中)。