如何判断 tcolorbox 中的参数是否为空?

如何判断 tcolorbox 中的参数是否为空?

我正在定义一个带有库的 tcolorbox 环境xparse

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{xparse}
\DeclareTColorBox[auto counter, number within=section]{mybox}{g}
  {title={mybox \thetcbcounter}, IfValueT={#1}{label={mybox:#1}}}
\begin{document}
\section{test}
\begin{mybox}{}
  \ref{mybox:}
\end{mybox}
\begin{mybox}{label}
  \ref{mybox:label}
\end{mybox}
\end{document}

在此处输入图片描述

我希望这个框有一个带前缀的标签mybox:。如果我写

\begin{mybox}
  test
\end{mybox}

没有标签。但是如果我写

\begin{mybox}{}
  test
\end{mybox}

会出现类似上面mwe这样的标签mybox:,如果出现多个这样的环境,就会有Multiply-defined label警告。

我怎样才能使空白参数{}与无参数具有相同的作用?

答案1

不要使用g参数类型:它已被弃用。

只需使用标准可选参数:

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{xparse}

\NewTColorBox[auto counter, number within=section]{mybox}{o}
  {
   title={mybox \thetcbcounter},
   IfValueT={#1}{label={mybox:#1}},
  }

\begin{document}

\section{test}

\begin{mybox}
  test
\end{mybox}

\begin{mybox}[label]
  \ref{mybox:label}
\end{mybox}

\end{document}

你将无法从第一个代码中获益

\begin{mybox}{}
  test
\end{mybox}

但是如果你真的坚持的话,代码可以

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{xparse}

\NewTColorBox[auto counter, number within=section]{mybox}{g}
  {
   title={mybox \thetcbcounter},
   IfValueT={#1}{mylabel=#1},
  }
\tcbset{
  mylabel/.code={
    \IfBlankTF{#1}{}{\tcbset{label={mybox:#1}}}%
  }
}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\IfBlankTF}{mmm}
  {
    \tl_if_blank:nTF { #1 } { #2 } { #3 }
  }
\ExplSyntaxOff

\begin{document}

\section{test}

\begin{mybox}{}
  test
\end{mybox}

\begin{mybox}
  test
\end{mybox}

\begin{mybox}{label}
  \ref{mybox:label}
\end{mybox}

\end{document}

.aux文件将具有

\relax 
\@writefile{toc}{\contentsline {section}{\numberline {1}test}{1}{}\protected@file@percent }
\newlabel{mybox:label}{{1.3}{1}}
\gdef \@abspage@last{1}

因此空参数没有标签。

无论如何,第一种方法是更好的选择。确实如此。

还要注意\NewTColorBox,因为\DeclareTColorBox会默默地覆盖具有相同名称的现有环境。

答案2

xparse区分可选参数缺失时的值和赋值空值时的值,\newcommand而它的朋友则不会。

\IfValueTF{<arg>}{<true>}{<false>}检查是否<arg>缺失(具有值-NoValue--11 N11 o11 V11 a11 l11 u11 e11 -12,请注意第一个的特殊 catcode -)。expl3\c_novalue_tl发挥\tl_if_novalue:nTF类似的作用。

要检查参数是否为空,\ifstremptyfrometoolbox满足要求。由于tcolorbox已经加载etoolbox,因此无需加载两次。

模仿如何tcolorbox提供选项IfValue(TF)作为 的包装器\IfValue(TF),这里有一个提供 包装器的示例\ifstrempty(参数类型g替换为o):

% tcbxparse.code.tex
\tcbset{
  IfNoValueTF/.code n args={3}{\IfNoValueTF{#1}{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}},
  IfNoValueT/.code n args={2}{\IfNoValueT{#1}{\pgfkeysalso{#2}}},
  IfNoValueF/.code n args={2}{\IfNoValueF{#1}{\pgfkeysalso{#2}}},
  IfValueTF/.code n args={3}{\IfValueTF{#1}{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}},
  IfValueT/.code n args={2}{\IfValueT{#1}{\pgfkeysalso{#2}}},
  IfValueF/.code n args={2}{\IfValueF{#1}{\pgfkeysalso{#2}}},
}
\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{xparse}

\tcbset{
  ifstrempty/.code n args={3}{\ifstrempty{#1}{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}},
}

\DeclareTColorBox[auto counter, number within=section]{mybox}{ o }
  {
    title={mybox \thetcbcounter},
    % add label only if #1 has value and is non empty
    IfNoValueTF={#1}{}{ifstrempty={#1}{}{label={mybox:#1}}}
  }

\begin{document}
\section{test}
\begin{mybox}
\end{mybox}

\begin{mybox}[]
\end{mybox}

\begin{mybox}[label]
\end{mybox}

\ref{mybox:}, \ref{mybox:label}
\end{document}

在此处输入图片描述

嗯,问题标题问的是“如何确定...是否空白的“。空白表示为空 ( \mybox[]) 或仅有空格 ( \mybox[ ])。您可以定义一个\ifblank类似的包装器。

答案3

我可以定义一个新的 tcolorbox 键来满足我的需求。

\documentclass{article}
\usepackage{etoolbox}
\usepackage{tcolorbox}
\tcbuselibrary{xparse}
\tcbset{
  mylabel/.code n args={1}
    {
      \def\temp{#1}
      \ifdefempty{\temp}{}{
        \tcbset{label={mybox:#1}}
        }
    }
}
\DeclareTColorBox[auto counter, number within=section]{mybox}{g}
  {title={mybox \thetcbcounter}, IfValueT={#1}{mylabel={#1}}}
\begin{document}
\section{test}
\begin{mybox}{}
  test
\end{mybox}
\begin{mybox}
  test
\end{mybox}
\begin{mybox}{label}
  \ref{mybox:label}
\end{mybox}
\end{document}

我可以在新的key中做空的判断mylabel,问题解决。

相关内容