我正在定义一个带有库的 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 N
11 o
11 V
11 a
11 l
11 u
11 e
11 -
12,请注意第一个的特殊 catcode -
)。expl3
并\c_novalue_tl
发挥\tl_if_novalue:nTF
类似的作用。
要检查参数是否为空,\ifstrempty
frometoolbox
满足要求。由于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
,问题解决。