我使用以下代码来检查包是否已加载:
\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@ifpackageloaded
)ltxcmds
和\@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
正如其他人所说,内核提供\@ifpackageloaded
并ltxcmds
也\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
在执行第二和第三个参数中的代码时不会留下任何尾随。