使用 siunitx 检测某个单元是否定义

使用 siunitx 检测某个单元是否定义

我正在使用该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 得出:

在此处输入图片描述

笔记:

代码:

\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

相关内容