我正在使用该siunitx
包并尝试检测是否定义了单元。我最初的假设是,这将只是:
\ifcsdef{#1}{#1 exists.}{#1 does NOT exist.}
如果单位声明为不是推迟到\AtBeginDocument
。因此,单位定义为
\DeclareSIUnit\milliliter{\textnormal{mL}}% <--- Can detect this just fine
\AtBeginDocument{%
\DeclareSIUnit\centiliter{\textnormal{cL}}% <--- But fails with this?
}%
检测\milliliter
很好,但检测\centiliter
并不容易。下面的 MWE 得出:
笔记:
- 我需要推迟一些定义,
\AtBeginDocument
直到 如何覆盖 siunitx 的二进制前缀并希望有一种方法来检测它们。
代码:
\documentclass{article}
\usepackage{etoolbox}
\usepackage{siunitx}
\DeclareSIUnit\milliliter{\textnormal{mL}}% <--- Can detect this just fine
\AtBeginDocument{%
\DeclareSIUnit\centiliter{\textnormal{cL}}% <--- But fails with this?
}
\newcommand*{\TestIfUnitExists}[1]{%
\par
\ifcsdef{#1liter}{%
#1liter exists.
}{%
#1liter does NOT exist.
}%
}%
\begin{document}
\TestIfUnitExists{giga}%
\TestIfUnitExists{milli}% <--- milliliter exists
\TestIfUnitExists{centi}% <--- centiliter also exists (but test fails)
\TestIfUnitExists{}% <--- liter exists as well
\end{document}
答案1
测试方法如下应该定义:
\documentclass{article}
\usepackage{siunitx}
\DeclareSIUnit\milliliter{\textnormal{mL}}
\AtBeginDocument{%
\DeclareSIUnit\centiliter{\textnormal{cL}}%
}
\ExplSyntaxOn
\NewDocumentCommand{\testifunitexistsTF}{smmm}
{
\IfBooleanTF{#1}
{ \grill_test_siunit:cTF {#2}{#3}{#4} }
{ \grill_test_siunit:NTF {#2}{#3}{#4} }
}
\cs_new_protected:Nn \grill_test_siunit:NTF
{
\seq_if_in:NnTF \l__siunitx_declare_list_seq { #1 } { #2 } { #3 }
}
\cs_generate_variant:Nn \grill_test_siunit:NTF { c }
\ExplSyntaxOff
\newcommand{\test}[1]{%
\testifunitexistsTF*{#1liter}{#1liter exists}{#1liter doesn't exist}%
}
\begin{document}
\section{General command}
\texttt{\string\millimeter} \testifunitexistsTF{\milliliter}{exists}{doesn't exist}
\texttt{\string\millimeter} \testifunitexistsTF*{milliliter}{exists}{doesn't exist}
\section{Test}
\test{giga}%
\test{milli}% <--- milliliter exists
\test{centi}% <--- centiliter also exists (but test fails)
\test{}% <--- liter exists as well
\end{document}
不幸的是,存储所有单位的序列变量不是公开的,因此无法真正使用。请向 Joseph Wright 提交功能请求,以使单位列表可搜索。
这是一个基于另一个答案的不同实现,但不会在范围内排版任何内容\si
。与以前的解决方案不同,宏\testifunitexists
仅接受名称作为参数,而不是控制序列。
\documentclass{article}
\usepackage{etoolbox}
\usepackage{siunitx}
\DeclareSIUnit\milliliter{\textnormal{mL}}
\AtBeginDocument{%
\DeclareSIUnit\centiliter{\textnormal{cL}}%
}
\newtoggle{unitexists}
\newcommand{\testifunitexistsTF}[1]{%
\global\togglefalse{unitexists}%
\sbox0{\si{%
\ifcsdef{#1}{\global\toggletrue{unitexists}}{}%
}}%
\iftoggle{unitexists}%
}
\newcommand{\test}[1]{%
\testifunitexistsTF{#1liter}{#1liter exists}{#1liter doesn't exist}%
}
\begin{document}
\section{General command}
\texttt{\string\millimeter} \testifunitexistsTF{milliliter}{exists}{doesn't exist}
\section{Test}
\test{giga}%
\test{milli}% <--- milliliter exists
\test{centi}% <--- centiliter also exists (but test fails)
\test{}% <--- liter exists as well
\end{document}
答案2
这种不同行为的原因似乎是如何处理未在/命令siunitx
范围内调用的新单元。如果我们在文档开始后立即使用 LaTeX 定义,我们会得到\si
\SI
\show
> \milliliter=\protected\long macro:
->\ERROR .
l.27 \show\milliliter
> \centiliter=undefined.
l.28 \show\centiliter
因此,\milliliter
被定义为未定义的控制序列,而\centiliter
奇怪的是,实际上未定义。您的测试无法识别此额外的间接层。
\si
一个简单的解决方案是当所有新单元都在范围内时在命令上下文中调用测试:
\newcommand*{\TestIfUnitExists}[1]{%
\par
\si{%
\ifcsdef{#1liter}{%
#1liter exists.
}{%
#1liter does NOT exist.
}%
}%
}%
答案3
定义的单元按siunitx
顺序在内部进行跟踪。这是不是公开,但由于您的用例看起来有些奇怪,我想您可能会这样做
\ExplSyntaxOn
\NewDocumentCommand \TestIfUnitExists { m }
{
\seq_if_in:NxTF \l__siunitx_declare_list_seq { \exp_not:c { #1 liter } }
{ #1liter~exists. }
{ #1liter~does NOT exist. }
}
\ExplSyntaxOff