LaTeX/宏
使用您迄今为止学到的命令生成的文档对于大多数读者来说看起来是可以接受的。虽然它们看起来并不花哨,但它们遵循所有已确立的良好排版规则,这将使它们易于阅读,并且看起来很舒适。但是,在某些情况下,LaTeX 没有提供与您的需求匹配的命令或环境,或者某些现有命令产生的输出可能不符合您的要求。
在本章中,我们将尝试提供一些关于如何教 LaTeX 新技巧以及如何使其生成与默认情况下提供的输出不同的输出的提示。
与纯 TeX 相比,LaTeX 是一种相当高级的语言,因此受到更多限制。下一章 将重点介绍纯 TeX,并解释用于编程的高级技术。
新命令
[edit | edit source]要添加您自己的命令,请使用
\newcommand{\name}[num]{definition}
|
命令。基本上,该命令需要两个参数:要创建的命令的名称(以反斜杠开头)和命令的定义。请注意,命令名称可以但不必用花括号括起来,随你喜欢。方括号中的num 参数是可选的,它指定新命令接受的参数数量(最多可以接受 9 个参数)。如果缺失,则默认为 0,即不允许参数。
以下两个示例将帮助您了解这个概念。第一个示例定义了一个名为\wbal的命令,它将打印“关于 LaTeX 的维基教科书”。如果您需要一遍又一遍地编写本书的标题,那么这样的命令可能很有用。
\newcommand{\wbal}{The Wikibook about \LaTeX}
This is ‘‘\wbal'' \ldots{} ‘‘\wbal''
|
这是“关于 LaTeX 的维基教科书”……“关于 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}
% in the document body:
\begin{itemize}
\item \wbalsup{Wikimedia}
\item \wbalsup{lots of users!}
\item \wbalTwo{John Doe}{Anthea Smith}
\end{itemize}
|
|
将您的新命令命名为 \wbalTwo
,而不是 \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}!}
% in the document body:
\begin{itemize}
\item \wbalTwo{John Doe}
\item \wbalTwo[lots of users]{John Doe}
\end{itemize}
|
|
- 注意
- 当使用显式第一个参数使用命令时,它将用方括号括起来(这里为 "[lots of users]")。
这是一个常见的示例:如果您正在撰写一本关于数学的书籍,并且必须使用向量,则必须决定它们的外观。许多书籍中使用了许多不同的标准。如果a 是一个向量,有些人喜欢在它上面添加一个箭头 (),其他人则用下划线表示它(a);另一种常见版本是用粗体表示它(a)。假设您想用箭头在上面写您的向量;然后在您的mystyle.sty.
\newcommand{\myvec}[1]{\vec{#1}}
|
文件中添加以下行,并在新的 \myvec{...}
命令中编写您的向量。您可以根据自己的意愿命名它,但最好选择一个简短的名称,因为您可能会经常编写它。然后,如果您改变主意,并且希望您的向量看起来不同,您只需更改 \myvec{...}
的定义。只要有可能就使用这种方法:这将为您节省大量时间,并提高文档的一致性。
DeclareRobustCommand
[edit | edit source]有些命令是脆弱的,也就是说它们在某些环境中会失败。如果一个宏在正文文本中有效但在(例如)图标题中无效,那么值得尝试将 \newcommand{\MyCommand}...
声明替换为前言中的 \DeclareRobustCommand{\MyCommand}...
。这对于在扩展时会生成写入到.aux文件的文本的宏尤其重要。
用于段落和数学模式的新命令
假设您要声明一些变量,您希望在段落中以及在数学模式中使用它。这可以通过在 Latex2e 中使用 \ensuremath
命令来实现,如下所示
\newcommand{\mysym}{\ensuremath{a^{2}+y^{2}}}
\newcommand 后面的空格
在定义的新命令后出现不一致的空格是一个常见问题。
例如: "动量是使用 p=mv 计算的。" 请注意公式后面没有空格。
另一方面 "公式 p=mv 计算动量。", 公式后面有空格。
针对此间距问题,可以使用 xspace 包,它会自动决定是否应该在其后添加空格。
\usepackage{xspace}
\newcommand{\restenergy}{\ensuremath{mv}\xspace}
新环境
[edit | edit source]与 \newcommand
命令一样,有一个命令可以创建您自己的环境。 \newenvironment
命令使用以下语法
\newenvironment{name}[num][default]{before}{after}
|
此外,\newenvironment
可以有一个可选参数。当遇到 \{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}
|
额外空格
[edit | edit source]在创建新环境时,你可能会很容易地被潜入的额外空格所困扰,这可能会产生致命的影响。一个例子是,当你想要创建一个标题环境,它抑制它自己的缩进以及下一段的缩进。环境的开始块中的 \ignorespaces
命令将使它忽略执行开始块后的任何空格。结束块有点棘手,因为在环境结束时会进行特殊处理。使用 \ignorespacesafterend
,LaTeX 将在特殊“结束”处理发生后发出一个 \ignorespaces
。
\newenvironment{simple}%
{\noindent}%
{\par\noindent}
\begin{simple}
See the space\\to the left.
\end{simple}
Same\\here.
|
See the space to the left. Same here. |
\newenvironment{correct}%
{\noindent\ignorespaces}%
{\par\noindent%
\ignorespacesafterend}
\begin{correct}
No space\\to the left.
\end{correct}
Same\\here.
|
No space to the left. Same here. |
此外,如果你在使用时仍然遇到在环境末尾附加额外空格的问题\input用于外部资源,确保环境的开头、资源和结尾之间没有空格,例如
\begin{correct}\input{somefile.tex}\end{correct}
|
或
\begin{correct}%
\input{somefile.tex}%
\end{correct}
|
在新环境中声明命令
[edit | edit source]新的命令可以在 newenvironment 中声明。在 newenvironment 中声明的命令通过加倍 # 字符来引用它们的 arguments。在下面的示例中,一个新的环境以及一个嵌套的命令被声明。
\newenvironment{topics}{
\newcommand{\topic}[2]{ \item{##1 / ##2} }
Topics:
\begin{itemize}
}
{
\end{itemize}
}
|
如果错误地将传递给 \topics 宏的 arguments 定义为单个 # 字符,则会抛出以下错误消息。
! Illegal parameter number in definition of \topics.
环境内容作为宏参数
[edit | edit source]一些命令(例如 \verb
、\textbf
和 \fcolorbox
)期望要修改的文本作为参数传递,因此不能放在环境定义的“头部”或“尾部”。在某些情况下,一个解决方法是使用相应的环境,例如 \{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}
|
扩展参数数量
[edit | edit source]xkeyval 包允许你为命令定义键值选项。
\mycommand[key1=value1, key3=value3]{some text}
|
这个包相当完整,文档也很详尽。我们建议包开发者阅读它。 [1]
让我们提供一个简单的例子[1]
\usepackage{xkeyval}
% ...
\makeatletter
\def\my@emphstyle#1{\csname my@style@#1\endcsname}
%% Predefined styles
\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}
|
算术
[edit | edit source] 一位读者要求扩展此页面以包含更多内容。 你可以通过添加新材料(了解如何)或在阅览室寻求帮助。 |
LaTeX 可以操作数字。
calc 包提供了常见的 infix 符号。
\usepackage{calc}
% ...
\newcounter{mine}
\setcounter{mine}{2*17}
\themine
|
对于高精度计算,你可以使用 fp[2] 包。
\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
\]
% High precision
\[
\FPdiv\result{17}{7}
\frac{17}{7} \approx \FPtrunc\result\result{3}
\result
\]
|
条件语句
[edit | edit source]LaTeX 可以使用条件语句,这要归功于 ifthen 包。
\usepackage{ifthen}
% ...
\ifthenelse{ \equal{\myvar}{true} }{
This is true.
}{
This is false.
}
|
FYI:对于较新的项目,推荐使用 e-TeX[3],它从 etoolbox 中的 LaTeX 可用。请参见其手册的 3.6 节。
以下是一个简短的示例,一个每次使用时都会切换状态的 bool 值。[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}
|
循环
[edit | edit source]PGF/TikZ 扩展提供了 \foreach
命令。
\usepackage{tikz}
% ...
\foreach \i/\q in {wheat/50g, water/1L, yeast/2g}{
\noindent\i\dotfill\q\\
}
|
如果你只使用 \foreach
而不绘制图形,你可以直接使用 pgffor
包。
或者,你可以查看 multido 包。
字符串
[edit | edit source]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 钩子
[edit | edit source]LaTeX 提供了两个钩子
\AtBeginDocument
允许你指定一组命令,这些命令将在遇到\{document}
时执行。\AtEndDocument
对\end{document}
执行相同的操作。
这为你提供了更多宏的灵活性。它可以用于覆盖在序言之后执行的设置。这些钩子可以调用多次。这些命令将按照设置的顺序执行。
例如,让我们用 oldstylenums 替换页码。
\usepackage{textcomp}
\AtBeginDocument{%
% Make the page numbers in text figures
\let\myThePage\thepage
\renewcommand{\thepage}{ \oldstylenums{\myThePage} }
}
|
还有一些针对类和包的钩子。请参见创建包。
命令行 LaTeX
[edit | edit source]如果你在类 Unix 操作系统上工作,你可能正在使用 Makefile 或任何类型的脚本构建你的 LaTeX 项目。在这种情况下,通过使用命令行参数调用 LaTeX,生成同一个文档的不同版本可能很有趣。如果你在文档中添加以下结构
\usepackage{ifthen}
%...
% default value.
\providecommand\blackandwhite{false}
%...
\ifthenelse{ \equal{\blackandwhite}{true} }{
% "black and white" mode; do something..
}{
% "color" mode; do something different..
}
|
现在你可以像这样调用 LaTeX
latex '\providecommand{\blackandwhite}{true}\input{test.tex}'
首先定义命令 \blackandwhite
,然后使用 input 读取实际文件。通过将 \blackandwhite
设置为 false,可以生成文档的彩色版本。