LaTeX
通过您到目前为止学到的命令所生成的文档将适合大多数受众。虽然它们看起来不够花哨,但遵循了良好的排版规则,这使得它们易于阅读和赏心悦目。然而,有些情况下,LaTeX 并没有提供符合您需求的命令或环境,或者某些现有命令生成的输出可能不符合您的要求。
在本章中,我们将尝试提供一些提示,教您如何让 LaTeX 学习新技巧,并使其生成与默认输出不同的效果。
LaTeX 相比于 Plain TeX 是一种相对较高级的语言,因此它的限制也更多。下一章将重点讨论 Plain TeX,并解释编程的高级技巧。
新命令
要添加您自己的命令,请使用以下命令:
\newcommand{\name}[num]{definition}
基本上,该命令需要两个参数:您要创建的命令的名称(以反斜杠开头)和命令的定义。请注意,命令名称可以(但不必)用大括号括起来,具体取决于您的需求。方括号中的 num
参数是可选的,指定新命令接受的参数个数(最多可以接受 9 个)。如果省略,默认值为 0,即不允许参数。
以下两个示例帮助您理解该概念。第一个示例定义了一个新命令 \wbal
,该命令将打印 “The Wikibook about LaTeX”。如果您需要多次写出此书的标题,这样的命令会非常有用。
\newcommand{\wbal}{The Wikibook about \LaTeX}
输出如下:
This is ‘‘\wbal'' \ldots{} ‘‘\wbal''
输出:
This is “The Wikibook about LaTeX” … “The Wikibook about LaTeX”
下一个示例展示了如何定义一个接受一个参数的新命令。#1
标签将被您指定的参数替换。如果您想使用多个参数,请使用 #2
,依此类推,这些参数将被添加到额外的一组括号中。
\newcommand{\wbalsup}[1] {
This is the Wikibook about LaTeX
supported by #1}
\newcommand{\wbalTwo}[2] {
This is the Wikibook about LaTeX
supported by #1 and #2}
在文档正文中:
\begin{itemize}
\item \wbalsup{Wikimedia}
\item \wbalsup{lots of users!}
\item \wbalTwo{John Doe}{Anthea Smith}
\end{itemize}
输出:
This is the Wikibook about LaTeX supported by Wikimedia
This is the Wikibook about LaTeX supported by lots of users!
This is the Wikibook about LaTeX supported by John Doe and Anthea Smith
注意:命名新命令时要避免使用数字,如命名为 \wbal2
是不合法的,因为数字不能用来命名宏 —— 无效字符将在编译时引发错误。
LaTeX 不允许您创建一个会覆盖现有命令的新命令。但如果您确实需要这样做,可以使用一个特殊命令:\renewcommand
,它的语法与 \newcommand
相同。
在某些情况下,您可能还想使用 \providecommand
命令。它与 \newcommand
类似,但如果命令已经定义,LaTeX 会默默忽略新命令。
在 LaTeX2e 中,您还可以使用以下语法为命令添加默认参数:
\newcommand{name}[num][default]{definition}
如果 \newcommand
的默认参数存在,则指定的 num
参数中的第一个参数是可选的,默认值为 default
;如果不存在,则所有参数都是必需的。
\newcommand{\wbalTwo}[2][Wikimedia]{
This is the Wikibook about LaTeX
supported by {#1} and {#2}!}
在文档正文中:
\begin{itemize}
\item \wbalTwo{John Doe}
\item \wbalTwo[lots of users]{John Doe}
\end{itemize}
输出:
This is the Wikibook about LaTeX supported by Wikimedia and John Doe!
This is the Wikibook about LaTeX supported by lots of users and John Doe!
注意
当命令使用显式的第一个参数时,它会被括号包围(例如 "[lots of users]")。
以下是一个常见的例子:如果您正在写一本关于数学的书,并且需要使用向量,您需要决定它们的外观。有几种不同的标准,在许多书籍中都有使用。如果 a
是一个向量,有些人喜欢在其上方加一个箭头(),有些人则写作带下划线的形式();另一种常见的方式是将其写为粗体()。假设您想使用带箭头的向量,那么可以在 mystyle.sty
文件中添加以下行:
\newcommand{\myvec}[1]{\vec{#1}}
然后将您的向量写在新的 \myvec{...}
命令中。您可以按自己的意愿命名,但最好选择一个简短的名称,因为您可能会非常频繁地使用它。然后,如果您改变主意,想让向量的样式不同,您只需要更改 \myvec{...}
的定义。只要您能使用这种方法,它将节省您大量的时间,并提高文档的一致性。
DeclareRobustCommand
有些命令是脆弱的,即它们在某些环境中不起作用。如果一个宏在正文中有效,但在(例如)图形标题中不起作用,值得尝试用 \DeclareRobustCommand{\MyCommand}...
替换 \newcommand{\MyCommand}...
声明。这对于那些在展开时生成文本并写入 .aux
文件的宏尤其有效。
在段落模式和数学模式中都能工作的新命令
假设您想声明一个变量,在段落模式和数学模式中都能使用。可以通过 LaTeX2e 中的 \ensuremath
命令实现:
\newcommand{\mysym}{\ensuremath{a^{2}+y^{2}}}
在 \newcommand
后面的空格
在定义新命令后,常见的问题是空格不符合规范。
考虑一下这个例子:“The momentum is calculated using 。”注意公式后面没有空格。
另一方面,“The formula calculates the momentum.” 公式后面有空格。
对于这个空格问题,可以使用 xspace
包,它会自动决定是否需要在命令后添加空格。
\usepackage{xspace}
\newcommand{\restenergy}{\ensuremath{mv}\xspace}
新环境
就像使用 \newcommand
命令一样,也有一个命令可以创建您自己的环境。\newenvironment
命令使用以下语法:
\newenvironment{name}[num][default]{before}{after}
同样,num
和 default
参数是可选的。begin{name}
命令(用于开始环境)会在处理环境中的文本之前处理 before
参数中指定的内容。当遇到 end{name}
命令(用于结束环境)时,after
参数中的内容会被处理。
num
和 default
参数的使用方式与 \newcommand
命令中的相同。LaTeX 会确保您不会定义一个已经存在的环境。如果您想要更改一个已存在的环境,可以使用 \renewenvironment
命令。它的语法与 \newenvironment
命令相同。
以下示例展示了如何使用 \newenvironment
命令:
\newenvironment{king}
{ \rule{1ex}{1ex}\hspace{\stretch{1}} }
{ \hspace{\stretch{1}}\rule{1ex}{1ex} }
\begin{king}
My humble subjects \ldots
\end{king}
多余的空格
创建新环境时,您可能会遇到多余的空格问题,这可能会导致致命的效果。一个例子是,当您想创建一个标题环境,并且希望它既不缩进也不影响下一个段落的缩进时,您可以在环境的 begin
块中使用 \ignorespaces
命令,以忽略执行 begin
块后的任何空格。end
块的处理稍微复杂一些,因为在环境的结束时会进行特殊的处理。使用 \ignorespacesafterend
,LaTeX 会在执行特殊的“结束”处理后发出 \ignorespaces
。
\newenvironment{simple}%
{\noindent}%
{\par\noindent}
\begin{simple}
See the space\\to the left.
\end{simple}
输出:
See the space
to the left.
Same
here.
\newenvironment{correct}%
{\noindent\ignorespaces}%
{\par\noindent%
\ignorespacesafterend}
\begin{correct}
No space\\to the left.
\end{correct}
输出:
No space
to the left.
Same
here.
此外,如果您在使用 \input
从外部源加载内容时仍然遇到多余的空格问题,请确保环境的开始、源和结束之间没有空格,例如:
\begin{correct}\input{somefile.tex}\end{correct}
或者:
\begin{correct}%
\input{somefile.tex}%
\end{correct}
在新环境中声明命令
新命令可以在 newenvironment
中声明。在 newenvironment
中声明的命令通过双倍的 #
来引用其参数。在以下示例中,声明了一个新环境,并嵌套了一个命令:
\newenvironment{topics}{
\newcommand{\topic}[2]{ \item{##1 / ##2} }
Topics:
\begin{itemize}
}
{
\end{itemize}
}
如果由于错误,传递给 \topics 宏的参数使用了单个 # 字符,将会出现以下错误消息:
! Illegal parameter number in definition of \topics.
环境内容作为宏参数
某些命令(例如,\verb
、\textbf
和 \fcolorbox
)要求修改的文本作为参数传递,因此不能放在环境定义的“头部”或“尾部”。在某些情况下,解决方法是使用相应的环境,例如:\begin{verbatim}...\end{verbatim}
对应于 \verb
。如果没有相应的环境,另一种替代方法是使用 environ
包,它将环境内容放入本地宏 \BODY
中。在以下示例中,makebold
环境将其内容加粗:
\documentclass{article}
\usepackage{environ}
\NewEnviron{makebold}{\textbf{\BODY}}
\begin{document}
\begin{makebold}
Some bold text.
\end{makebold}
\end{document}
扩展参数数量
xkeyval
包允许您为命令定义键/值选项。
\mycommand[key1=value1, key3=value3]{some text}
该包非常完整,文档也非常详尽。我们建议包的开发者阅读它。[1]
下面是一个简单的示例[1]:
\usepackage{xkeyval}
% ...
\makeatletter
\def\my@emphstyle#1{\csname my@style@#1\endcsname}
%% 预定义样式
\providecommand\my@style@default{\em}
\providecommand\my@style@bold{\bfseries}
\define@key{myemph}{code}{%
\def\my@emphstyle{#1}
}
\define@key{myemph}{style}{%
\def\my@emphstyle{\csname my@style@#1\endcsname}
}
\newcommand\setemph[1]{%
\setkeys{myemph}{#1}
}
\renewcommand\emph[1]{%
{\my@emphstyle #1}
}
\makeatother
输出示例:
Something \emph{important}
\setemph{style=bold}
Something \emph{important}
\setemph{code=\Large\sffamily}
Something \emph{important}
算术
读者要求扩展此页以包含更多内容。
您可以通过添加新内容来帮助(了解如何)或请求在阅读室中获得帮助。
LaTeX 可以操作数字。
calc
包提供了常见的中缀表示法。
\usepackage{calc}
% ...
\newcounter{mine}
\setcounter{mine}{2*17}
\themine
对于高精度计算,您可以使用 fp
包。
\usepackage{fp}
% Clip
\[
\FPmul\result{2}{7}
\FPclip\result\result
2*7 = \result
\]
% Infix
\[
\newcommand\result{11}
\sqrt{\sin(2+\result)} \approx
\FPeval\result{round(root(2,sin(result + 2.5)),2)}
\result
\]
% Postfix
\[
\FPupn\result{17 2.5 + 17.5 swap - 2 1 + * 2 swap /} % or \FPupn\result{2 17.5 17 2.5 + - 2 1 + * /}
\FPclip\result\result
(17+2.5 - 17.5) * (2+1) / 2 = \result
\]
% 高精度
\[
\FPdiv\result{17}{7}
\frac{17}{7} \approx \FPtrunc\result\result{3}
\result
\]
条件判断
LaTeX 可以使用条件语句,感谢 ifthen
包的支持。
\usepackage{ifthen}
% ...
\ifthenelse{ \equal{\myvar}{true} }{
This is true.
}{
This is false.
}
提示:对于较新的项目,建议使用 e-TeX(可在 LaTeX 中通过 etoolbox
获得)。请参见它们手册的第 3.6 节。
以下是一个简单的示例,展示了一个每次使用时切换状态的布尔值。[4]
\documentclass{article}
\usepackage{etoolbox}
\usepackage{parskip}
\usepackage{tikz}
\newbool{volt}
\newcommand{\onoff}{%
\ifbool{volt}{%
\boolfalse{volt}\candleOn\space ON}{%
\booltrue{volt}\candleOff\space OFF}%
}
\newcommand{\candleOff}{\tikz \draw (0,0) rectangle (.2,.8);}
\newcommand{\candleOn}{\begin{tikzpicture}\draw (0,0) rectangle (.2,.8);\draw [fill=orange] (.1,.9) circle [radius=.1];\end{tikzpicture}
}
\begin{document}
\onoff\par
\onoff\par
\onoff\par
\onoff\par
\end{document}
循环
PGF/TikZ 扩展提供了 \foreach
命令。
\usepackage{tikz}
% ...
\foreach \i/\q in {wheat/50g, water/1L, yeast/2g}{
\noindent\i\dotfill\q\\
}
如果你只使用 \foreach
而不绘制图形,您也可以直接使用 pgffor
包。
另外,您可以查看 multido
包。
字符串
xstring
提供了许多功能。从 CTAN:
-
测试字符串的内容
-
提取子字符串
-
子字符串替换
-
字符串长度
-
子字符串的位置
-
子字符串的重复次数
示例:
\usepackage{xstring}
% ...
\newcommand\mystr{Hello World!}
The string ``\mystr'' has \StrLen{\mystr}{} characters.
Predicate ``\mystr{} contains the word Hello'' is \IfSubStr{\mystr}{Hello}{true}{false}.
LaTeX 挂钩
LaTeX 提供了两个挂钩:
-
\AtBeginDocument
让您指定在遇到\begin{document}
时执行的命令集。 -
\AtEndDocument
做同样的事情,但在\end{document}
时执行。
这为宏提供了更多灵活性。它在覆盖文档设置时尤其有用,特别是在执行前导部分之后。这些挂钩可以多次调用,命令会按照它们设置的顺序执行。
例如,我们可以用旧式数字替换页面编号:
\usepackage{textcomp}
\AtBeginDocument{%
% Make the page numbers in text figures
\let\myThePage\thepage
\renewcommand{\thepage}{ \oldstylenums{\myThePage} }
}
命令行 LaTeX
如果您在类似 Unix 的操作系统上工作,可能会使用 Makefile 或任何脚本来构建您的 LaTeX 项目。在这种情况下,使用命令行参数调用 LaTeX 来生成同一文档的不同版本可能会很有趣。如果您在文档中添加以下结构:
\usepackage{ifthen}
%...
% 默认值
\providecommand\blackandwhite{false}
%...
\ifthenelse{ \equal{\blackandwhite}{true} }{
% "黑白"模式; 做一些事情..
}{
% "彩色"模式; 做一些不同的事情..
}
现在,您可以像这样调用 LaTeX:
latex '\providecommand{\blackandwhite}{true}\input{test.tex}'
首先定义命令 \blackandwhite
,然后读取实际文件。通过将 \blackandwhite
设置为 false
,将生成文档的彩色版本。