如何实现检查多个已加载包的命令?

如何实现检查多个已加载包的命令?

我使用以下代码来检查包是否已加载:

\RequirePackage{ltxcmds}
\newcommand{\IfPackageLoaded}[2]{\ltx@ifpackageloaded{#1}{#2}{}}

但是,有时我想检查是否加载了多个包。因此,我想概括该命令,以便可以在用逗号分隔的列表中添加多个包:

\IfPackagesLoaded{xcolor, colortbl, hyperref}{
...
}%

处理这种列表的典型实现是什么样的?

答案1

您可以使用 LaTeX 内核的\@for宏(处理逗号分隔列表)与if开关结合使用。该\IfPackagesLoaded宏最初将开关设置为 true,然后遍历列表,如果缺少包,则将开关设置为 false。

\documentclass{article}

\usepackage{ltxcmds}

\usepackage{fixltx2e}
\usepackage{doc}

\makeatletter
\newif\ifallloaded
\newcommand{\IfPackagesLoaded}[3]{%
  \allloadedtrue
  \@for\@tempa:=#1\do{%
    \ltx@ifpackageloaded{\@tempa}{}{\allloadedfalse}}%
  \ifallloaded #2\else #3\fi}
\makeatother

\begin{document}

\IfPackagesLoaded{fixltx2e,doc}{yes}{no}
\IfPackagesLoaded{hyperref,fixltx2e}{yes}{no}

\end{document}

答案2

正如 Andrey 所说,您可以使用 LaTeX 内部宏\@for来遍历逗号分隔的列表。另一个有用的宏是\zap@space,它通常用于从包选项列表中删除空格。

我会定义一个\next宏,通常真的,即展开为接下来两个参数中的第一个,但如果遇到任何未加载的包,则展开为第二个。然后我重新定义一个内部宏(在组内)以跳过所有其他包。(包\lxt@ifpackageloadedltxcmds\@ifpackageloaded(LaTeX 核心,但仅在前言中)执行的包加载测试是检查宏是否\ver@<package>.sty定义,它保存包的版本(但可以为空)。我直接在这里添加了此代码,以便不依赖于包,只是为了这个小代码。

\documentclass{article}

\usepackage{fixltx2e}
\usepackage{doc}

\makeatletter
\newcommand{\IfPackagesLoaded}[1]{%
    \begingroup
    \let\next\@firstoftwo
    \@for\@tempa:=#1\do{%
        \expandafter\@IfPackagesLoaded\expandafter{\@tempa}%
    }%
    \expandafter\endgroup
    \next
}
\def\@IfPackagesLoaded#1{%
    \edef\@tempa{\zap@space#1 \@empty}% remove any spaces
    \expandafter\ifx\csname ver@\@tempa.sty\endcsname\relax% package not loaded?
        \let\next\@secondoftwo
        \let\@IfPackagesLoaded\@gobble% No need for further checks
    \fi
}
\makeatother

\begin{document}

\IfPackagesLoaded{fixltx2e,doc}{\typeout{yes}}{\typeout{no}}
\IfPackagesLoaded{ fixltx2e , doc }{\typeout{yes}}{\typeout{no}}
\IfPackagesLoaded{hyperref,fixltx2e}{\typeout{yes}}{\typeout{no}}

\end{document}

答案3

正如其他人所说,内核提供\@ifpackageloadedltxcmds\ltx@ifpackageloaded可以在文档中使用。

\usepackage{ltxcmds,etoolbox}

\makeatletter
\newcommand{\IfPackagesLoaded}[1]{%
  \@tempswatrue
  \def\do##1{\edef\@tempa{\zap@space##1 \@empty}%
    \ltx@ifpackageloaded{\@tempa}{}{\@tempswafalse}}%
  \docsvlist{#1}%
  \if@tempswa\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}
\makeatother

通过处理列表元素\zap@space可确保包名称周围没有空格,即使调用

\IfPackagesLoaded{ abc , xyz }

该条件\if@tempswa由 LaTeX 预定义,用作“临时条件”;它只应在立即应用时依赖,因为其他宏可能会改变其真值。这个想法是,条件在开始时设置为 true,列表中的每个“尚未加载”包将其设置为 false。因此,只有当列表中的所有包都已加载时,它在最后才会仍然为 true。

最后一行利用了这一事实,并使用了 的第二个或第三个参数中的代码\IfPackagesLoaded。实际上,它们并不是 的真正参数\IfPackagesLoaded,但从用户的角度来看,这没有什么区别。我可能已经\IfPackagesLoaded通过使用作为最后一条指令来定义三个参数

\if@tempswa#2\else#3\fi

但选择的方式更好,因为它不会留下任何尾随\else,或者\fi在执行第二和第三个参数中的代码时不会留下任何尾随。

相关内容