将 \ifxetex 和 \ifluatex 与逻辑或运算相结合

将 \ifxetex 和 \ifluatex 与逻辑或运算相结合

我想在 LaTeX 文档的序言中写入代码,这些代码应该被不同的编译器在排版文档时考虑。应该使用以下片段:

  • 仅限 xelatex
  • 仅限 lualatex
  • 仅由 xelatex 或 lualatex 提供
  • 仅由 pdflatex 提供

我正在使用ifxetexifluatex分别提供命令\ifxetex\ifluatex

我怎样才能在析取(or操作)中逻辑地组合这些命令?

代码如下:

\ifxetex
  % code used only by xetex
\else
  \ifluatex
    % code used only by luatex
  \fi
\fi

\ifxetex OR \ifluatex     % I do not know how to express this conditional <--------
  % code used by both xetex and luatex
\else
  % code used by other (pdflatex, say)
\fi

有什么帮助吗?

答案1

\usepackage{ifxetex,ifluatex}
\newif\ifxetexorluatex
\ifxetex
  \xetexorluatextrue
\else
  \ifluatex
    \xetexorluatextrue
  \else
    \xetexorluatexfalse
  \fi
\fi

现在\ifxetexorluatex就可以做你想做的事了。例如,加载fontspec和设置输入规范化:

\ifxetexorluatex
   \usepackage{fontspec}
   \setmainfont{TeX Gyre Pagella}
\else
   \usepackage[T1]{fontenc}
   \usepackage{tgpagella}
\fi

\ifxetex
  \XeTeXinputnormalization=1
\fi

为了好玩,还有一个不同的实现,

\newif\ifxetexorluatex
\begingroup\catcode94=7 \catcode0=9 % ASCII 94 is ^
\def\empty{}\def\next{^^^^0000}\expandafter\endgroup
\ifx\next\empty\xetexorluatextrue\else\xetexorluatexfalse\fi

它利用了 XeTeX 和 LuaTeX 引擎使用^^^^Unicode 点输入字符的惯例。如果引擎支持 Unicode,则^^^^0000被视为唯一标记,而赋值\catcode0=9会被忽略,因此\next会扩展为零,相当于\empty。如果使用 8 位引擎, 的扩展\next将包含六个标记(^^^算作一个,然后^0000),\ifx并将遵循“错误”路径。

另一种不定义条件的方法\ifxetexorluatex

\ifnum 0\ifxetex 1\fi\ifluatex 1\fi>0
   % code for XeTeX or LuaTeX
\else
   % code for pdfLaTeX
\fi

必须有0和之间\ifxetex以及1和之间的空格\fi。这利用了 TeX 在查找数字时会扩展标记的事实。因此,如果两个内部条件之一为真,则引擎将看到01,它大于零。如果两者都为假,它将看到0

因此,设置的一个更短的方法\ifxetexorluatex可以是

\newif\ifxetexorluatex % a new conditional starts as false
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi>0
   \xetexorluatextrue
\fi

使用 的更通用的实现expl3

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\cs_new_eq:NN \pdftexengine \sys_if_engine_pdftex_p:
\cs_new_eq:NN \xetexengine  \sys_if_engine_xetex_p:
\cs_new_eq:NN \luatexengine \sys_if_engine_luatex_p:
\cs_new_eq:NN \ptexengine   \sys_if_engine_ptex_p:
\cs_new_eq:NN \uptexengine  \sys_if_engine_uptex_p:

\NewExpandableDocumentCommand{\ifengineTF}{mmm}
 {
  \bool_if:nTF { #1 } { #2 } { #3 }
 }
\ExplSyntaxOff

\begin{document}

\ifengineTF{\pdftexengine}
  {\typeout{pdf}}
  {\typeout{not pdf}}

\ifengineTF{\xetexengine || \luatexengine}
  {\typeout{either xe or lua}}
  {\typeout{neither xe nor lua}}

\ifengineTF{\pdftexengine || \xetexengine || \luatexengine}
 {\typeout{pdf or xe or lua}}
 {\typeout{ptex or uptex}}

\end{document}

从 shell 运行以下命令

> pdflatex engines >> engines.out
> xelatex engines >> engines.out
> lualatex engines >> engines.out
> platex engines >> engines.out

生成以下engines.out文件(已编辑,仅显示相关部分)

This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
pdf
neither xe nor lua
pdf or xe or lua
[...]

This is XeTeX, Version 3.14159265-2.6-0.99999 (TeX Live 2018) (preloaded format=xelatex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
not pdf
either xe or lua
pdf or xe or lua
[...]

This is LuaTeX, Version 1.07.0 (TeX Live 2018) 
 restricted system commands enabled.
(./engines.tex
[...]
not pdf
either xe or lua
pdf or xe or lua
[...]

This is e-pTeX, Version 3.14159265-p3.8.1-180226-2.6 (utf8.euc) (TeX Live 2018) (preloaded format=platex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
not pdf
neither xe nor lua
ptex or uptex
(./engines.aux) )
[...]

一种不同的解决方案,可能具有更好的语法,但以牺牲可扩展性为代价(直到我们有可用e的-expansion)。

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\ifengineTF}{mmm}
 {
  \bool_if:xTF
   {
    \clist_map_function:nN { #1 } \__egreg_predicate:f \c_true_bool
   }
   { #2 } { #3 }
 }
\cs_generate_variant:Nn \bool_if:nTF { x }

\cs_new:Nn \__egreg_predicate:n
 {
  \use:c { sys_if_engine_#1_p: } ||
 }
\cs_generate_variant:Nn \__egreg_predicate:n { f }
\ExplSyntaxOff

\begin{document}

\ifengineTF{pdftex}
  {\typeout{pdf}}
  {\typeout{not pdf}}

\ifengineTF{xetex,luatex}
  {\typeout{either xe or lua}}
  {\typeout{neither xe nor lua}}

\ifengineTF{pdftex,xetex,luatex}
 {\typeout{pdf or xe or lua}}
 {\typeout{ptex or uptex}}

\end{document}

输出与以前相同。

答案2

在这种情况下\ifboolexpretoolbox包派上用场了:

\usepackage{etoolbox,ifxetex,ifluatex}

\ifboolexpr{bool{xetex} or bool{luatex}}{%
  <true-code>%
}{%
  <false-code>%
}

与执行布尔测试的语法配合使用的 bool 运算符\ifboolexpr可对所有原始样式的 TeX 条件进行操作。请注意,它省略了\if原始\ifxetexand\ifluatex命令的前缀。

答案3

有时,通过改变检查顺序,这类问题会更​​容易解决。

\documentclass{article}
\usepackage{ifpdf,ifluatex,ifxetex}
\begin{document}
\ifpdf
      I am in pdf
   \else
       common code for lualatex and xelatex
    \ifluatex  ...    \fi
    \ifxetex   ...    \fi
\fi
\end{document}

答案4

为了好玩,可能是最短的路:

\documentclass{article}
\usepackage{ifxetex,ifluatex}
\begin{document}

hello

\ifx\ifxetex\ifluatex\else
   xetex or luatex is true
\fi

\end{document}

确实,xetexluatex是互相排斥的。如果两个条件一致,那一定是因为两者都是假的。所以相反的情况是,两者之一为真,这正是所要求的。


正如评论中指出的那样egreg,这种构造不能在其他条件语句中原样使用(以防它最终进入跳过的分支)。这种替代表述没有这个缺陷:

\expandafter\ifx\csname ifxetex\expandafter\endcsname \csname ifluatex\endcsname\else 
xetex or luatex is true\fi

相关内容