有问题的例子\IfEmptyTF

有问题的例子\IfEmptyTF

考虑以下 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}

在此处输入图片描述


脚注

  1. 在读取第二个⟨dimen⟩时,没有扩大开始的风险#2,更重要的是,允许每一个电视F\IfEmptyTF{...}{T}{F}子句对输入流中跟在 后面的标记进行操作(在您的代码中,在输入流中#2跟在后面,并且跟在 后面,当您想要实现某些事情时,这可能会成为一大障碍——这在下有说明\else#3\fi有问题的例子\IfEmptyTF在这个答案中)。

相关内容