这是关于\(\LaTeX\)基础概念的笔记,不涉及具体的\(\LaTeX\)语法细节,而是从宏观层面,包括历史和命令行用法等,来进一步理解 \(\TeX\)\(\LaTeX\)

\(\TeX\)语言

\(\TeX\)排版系统是 Knuth 发明的一种宏语言,提供了几百个类似\def的基础指令用于排版,主要解决的是自动断行,以及公式布局等排版问题。\(\TeX\)语言的版本在升级到 3.0 之后,主版本号就不再发生变动,而是以 3.1,3.14,3.141 的形式在更新时不断接近 pi,这体现了\(\TeX\)语言的稳定性。

关于排版系统的基本介绍,有一篇博客可以参考: 排版引擎纵谈:程序员的视角

\(\TeX\)语言并不适合直接使用:

  • 最早设计时不支持非 ASCII 编码,更不要说 Unicode 字符和中文支持等
  • 字体需要额外配置,不能利用系统现有的字体
  • 原始的几百个基础指令太繁琐又太简陋,需要考虑很多细节

后续有很多基于\(\TeX\)基本指令封装的宏集,让使用者可以忽略很多细节,例如在 \(\LaTeX\) 格式中的 center 环境是如下编写的(在 latex.ltx 文件中)

1
2
\def\center{\trivlist \centering\item\relax}
\def\endcenter{\endtrivlist)

本质上是以一种非常底层的,类似 C 的宏的形式进行的指令扩展。典型的包括:

  • \(\text{plain}\,\TeX\):发明者 Knuth 提供的一套极简的\(\TeX\)的宏
  • \(\LaTeX\):使用最为广泛的一套宏,对科技文档的排版更加友好,它的当前版本为\(\LaTeX2_\varepsilon\),含义为尚未达到第三版
  • \(\text{AMS}\,\TeX\):AMS 提供的一套宏集,可以在\(\LaTeX\)中导入相关的宏包进行等效使用
  • \(\text{ConText}\):相比于\(\LaTeX\),更加自由灵活,也更复杂
  • ...

这些宏集非常全面,被称为格式,例如\(\LaTeX\)格式,在各种主流格式的基础上,仍然支持使用宏进行进一步的扩展,这些在\(\LaTeX\)中称为宏包 package,在\(\text{ConText}\)中称为模块 module,扩展包只提供了一部分功能,因此只适合在某个格式的基础上进行使用。

极简的\(\text{plain}\,\TeX\)例子

1
2
Hello, World
\bye

极简的\(\LaTeX\)例子

1
2
3
4
5
6
7
8
9
10
11
12
13
\documentclass{article}

\begin{document}

Hello, this is a simple \LaTeX{} document.
Here is an inline equation: $E=mc^2$, which is Einstein's famous equation.
And here is a displayed equation:

\[
\int_{0}^{\infty} e^{-x^2} \, dx = \frac{\sqrt{\pi}}{2}
\]

\end{document}

\(\TeX\)语言和\(\LaTeX\)格式的关系就像早期的 C 和 C++ 的关系,那时候 C++只是 C with class,C++之父在实现时只是做了一个转换:C++代码先经过处理将面向对象的部分改写为 C 的合法代码,然后传递给 C 的编译器。

\(\TeX\)编译器

\(\TeX\)语言只是规定了源文件的语法规范,相当于 C++11 之类的语法标准,但是具体通过源文件获得输出(dvi,ps,pdf 格式)还需要依赖编译器,就像 C/C++有多种主流编译器实现(gcc/msvc/clang),\(\TeX\)也是如此。 而且和 C++ 一样,对相同的源代码使用不同编译器编译,完全可能得到不同的输出,有时还会出现某个编译器编译失败的情况。

\(\TeX\)语言的实现最早是由发明者 Knuth 写的一个\(\TeX\)编译器(又称为\(\TeX\)引擎),后续又有很多或继承或独立的实现,典型的\(\TeX\)编译器包括:(这里为了区分,对于编译器和编译命令不再采用斜体)

  • (Knuth)TeX:发明者 Knuth 的原版\(\TeX\)编译器,现在几乎不使用
  • \(\varepsilon\)-TeX:相比于原始 Tex 提供了扩展功能,是事实上的标准\(\TeX\)编译器,后面的几个编译器都是基于它开发的
  • pdfTeX:西文期刊论文的排版最常用的,支持直接生成 pdf,默认只支持西文字符,项目开发者已经转向了 LuaTeX
  • XeTeX:支持 Unicode,支持直接调用系统字体的编译器,中文排版时最建议使用
  • pTeX:主要是日本人开发的,包括后续改进的 p 系列\(\TeX\)编译器
  • LuaTeX:支持 Lua 扩展,原生支持 Unicode 和系统字体的编译器,作为 pdfTeX 的正统后继者,仍然在开发中,并没有广泛采用,中文排版也可以使用(但是速度相比 XeTex 慢不少)

\(\TeX\)编译器支持接收不同的源文件格式作为输入,例如\(\text{plain}\,\TeX\)\(\LaTeX\),需要使用参数指定。\(\TeX\)编译器在早期设计时的输出为 dvi 文件或 ps 文件,如果需要 pdf 文件还需要进行一次转换,现代的主流编译器都可以直接产生这三种输出文件(pdf,dvi,ps),建议输出 pdf 文件。

在命令行直接使用\(\TeX\)编译器时,可以使用选项指明源文件的格式和输出文件格式,例如调用 pdftex 编译\(\LaTeX\)格式的源文件,要求输出为 pdf

1
pdftex -fmt=latex -out-format=pdf main.tex

如果不使用-fmt选项,源文件可能会被视作\(\text{plain}\,\TeX\)格式,如下的命令在编译时会出现错误,无法识别源文件中相关的命令

1
pdftex main.tex

使用 pdflatex 则默认指定\(\LaTeX\)格式,直接编译即可,输出的是 pdf 文件

1
pdflatex main.tex

注意:这些编译命令主要适配的是Linux,在Windows上有很多潜在问题,比如不支持.\main.tex的写法,必须使用Linux风格的文件分隔符 ./main.tex。因为宏通常以\开头,使用\可能产生很多问题。文件名和路径名最好不要含有中文。

不同编译器产生的 pdf 文件只是内容看起来一样,实际有很多区别,例如一些排版细节,pdf 文件的实际大小也可能有很大差异。 可以通过查看PDF的属性中的PDF Producer来检查实际采用的编译器,例如(版本号可能不同)

  • pdfTeX-1.40.25 对应 pdftex
  • xdvipdfmx (20220710) 对应 xetex
  • LuaTeX-1.16.0 对应 luatex

\(\TeX\)编译命令

将编译器和输入源文件格式,输出文件格式组合,就可以得到不同的具体编译命令:(通常直接使用的是某个编译命令而非编译器)

  • etex:pdfTex 编译器,输入\(\text{plain}\,\TeX\)格式,输出 dvi 文件
  • latex:pdfTex 编译器,输入\(\LaTeX\)格式,输出 dvi 文件
  • pdftex:pdfTex 编译器,输入\(\text{plain}\,\TeX\)格式,输出 pdf 文件
  • pdflatex:pdfTex 编译器,输入\(\LaTeX\)格式,输出 pdf 文件
  • xetex:XeTex 编译器,输入\(\text{plain}\,\TeX\)格式,输出 pdf 文件
  • xelatex:XeTex 编译器,输入\(\LaTeX\)格式,输出 pdf 文件
  • luatex:LuaTex 编译器,输入\(\text{plain}\,\TeX\)格式,输出 pdf 文件
  • lualatex:LuaTex 编译器,输入\(\LaTeX\)格式,输出 pdf 文件

(参考 lshort-zh-cn 教程)

这几种就是目前最常见的编译器选项,显然*latex编译命令都是默认支持\(\LaTeX\)格式的,并且都被 Overleaf 平台支持, 其中的xelatexlualatex支持 Unicode 编码和中文,后者支持添加 Lua 脚本进行扩展,但是测试发现lualatex编译明显偏慢。

关于Unicode编码的补充:有时可能从别的地方复制得到一些和常用字符很相似的Unicode字符,这可能直接导致pdflatex编译失败,xelatexlualatex更可能因为无法显示字符而将其忽略掉。

推荐的编译器选择如下:

  • 西文:pdflatex(考虑到期刊论文排版的要求)
  • 中文和中英文混合:xelatex

有的编译软件(例如TeXworks等)支持通过源文件头部的魔法注释指定采用的编译器(还支持提供其它信息),例如

1
2
3
4
5
6
7
8
% !TEX program = pdflatex
\documentclass{article}

\begin{document}

Hello, world!

\end{document}

\(\TeX\)发行版

发行版就是对\(\TeX\)编译器,以及其他常用宏包,辅助工具的完整封装,使用者通常是下载一整个发行版,而非单独配置。常见的发行版包括:

  • Tex Live:目前唯一推荐的最主流的发行版,多平台支持,在 MacOS 上是基于 Tex Live 的定制版本 MaxTex
  • MiKTex:只支持 Windows
  • CTex:在早期为了支持中文,基于 MiKTex 定制的一个 Windows 上的发行版,现在不推荐使用,同时不推荐的是CJK宏包。(注意还有名为 ctex 的宏包,和这里的发行版不是一回事)

这些发行版自身都附带了一个简单朴素的\(\LaTeX\)编辑器 TeXworks,更专业的\(\LaTeX\)编辑器是 Tex Studio 和 WinEdt, 也可以使用通用编辑器例如 vim/nvim 和 VSCode 加上 LaTeX 插件进行使用。

发行版通常都提供了管理宏包的工具,尽量使用它们提供的工具来下载和管理宏包,而非手动下载。 就像Anaconda之于Python, \(\TeX\)发行版已经自带了数千个常用或不常用的宏包,我们通常都不需要考虑宏包的下载更新等细节。 如果希望使用更新的发行版,推荐的做法不是升级,而是直接卸载旧版,然后安装新版。

在Windows上安装Tex Live时,如果用户主目录含有中文,或者安装位置含有中文,都可能导致安装失败。 因为主目录更改非常麻烦,可选的解决办法是在安装时重定义相关环境变量,使Tex Live绕开主目录。

\(\LaTeX\) 文档类

\(\LaTeX\)源代码通常以声明一个文档类开头

1
\documentclass[⟨options⟩]{⟨class-name⟩}

常见的文档类包括:(篇幅从小到大)

  • atricle
  • report
  • book

使用例如

1
2
3
4
5
\documentclass{article}

\documentclass[12pt]{article}

\documentclass[11pt,twoside,a4paper]{article}

此外还有 beamer 这种特殊的幻灯片形式的文档类。

如果有很多定制的格式需求,可以自行定制一个文档类(*.cls),自行设置各种排版细节,但是通常都是不需要的。

\(\LaTeX\)中文支持

ctex宏包是当前推荐的中文支持方案,它针对不同平台和不同编译器选择了不同的底层中文支持方案(CJK,xeCJK,luatexja等),让使用者可以忽略这些底层细节。

为了使用ctex支持中文,在源文件中有两种处理方法:

  • 第一种方法是导入 ctex 宏包(注意不是 CTex 发行版)

    1
    2
    3
    \documentclass{article}

    \usepackage[UTF8]{ctex}

  • 第二种方法是使用中文文档类:ctex 直接将 article 等基本文档类和 ctex 宏包以及其他宏包进行组合,并且进行了很多适合中文文档的细节调整(例如中文标点,中文间空格的处理等),提供 ctexart,ctexrep,ctexbook,ctexbeamer等中文文档类,导入时可以指定 UTF-8 编码也可以省略(默认就是UTF-8编码,并且对于XeLaTex和LuaLaTex是强制UTF-8编码)

    1
    2
    3
    \documentclass{ctexart}

    \documentclass[UTF8]{ctexart}

两种方法并不等价,有很多细微区别,建议选择方式为:

  • 轻度使用中文(即中英文混用)建议使用第一种;
  • 重度使用中文(即纯中文文档)则建议使用第二种。

此外,还需要保证:

  • 源代码使用 UTF-8 编码保存
  • 使用 xelatex(或 lualatex)编译

虽然 ctex 宏包和文档类保留了对 GBK 编码以及 pdflatex 编译命令的兼容,但并不推荐这样做。

在不同的编译器之间,实际有很多细微的差异,例如关于中文空格处理的细节: 对于中文字符后的空格,以及中文和西文字符之间的空格,XeLaTex 会直接忽略,但是 LuaLaTex 不会忽略,但是对于连续空格只显示一个。

除了编译器的差异,在不同的平台之间也有很多细微的差异(只考虑xelatex),例如默认使用的中文字体:

  • Windows平台默认的宋体是SimSun
  • Linux平台(包括Overleaf等在线平台)默认的宋体是FandolSong

对于不同平台得到的pdf,实际上在中文标题中就可以观察到明显的差异,这就是使用了不同的字体导致的。 如果平台上安装了相应的中文字体,也可以手动更改,例如使用下面的命令更改中文的正文字体

1
2
\setCJKmainfont{FandolSong}
\setCJKmainfont{SimSun}

在没有特殊需求时,不太需要关注或修改实际的中文字体,用默认的即可,对于最终提交的正式版采用Windows平台的SimSun字体更符合相应的规范。

补充

MathJax/KaTex

在网页上也有渲染数学公式的需求,而网页的排版系统主要是基于 HTML+CSS+JS 的,和 Tex 的排版功能是不同的,一个最明显的不同是,网页的排版通常没有分页和首行缩进的需求。

在涉及到数学公式的部分,网页上的渲染实现是调用符合 Tex 规范的 JS 引擎,例如 MathJax 或 KaTex,通过导入这些开源脚本来支持在网页上嵌入 LaTeX、MathML 或 AsciiMath 标记,并将其渲染为数学公式,其中 KaTex 更加轻量级,但是对复杂公式渲染效果还是 MathJax 更好。

至于 Markdown,只是简化的 HTML,使得样式和文本进一步分离,适合快速完成在网页中呈现的文档,例如博客等,对它的渲染还是转换为 HTML+CSS+JS 的,因此在 Markdown 中也可以使用一些 HTML 语句,Markdown 对 Tex/LaTex 的支持也是继承自 HTML+CSS+JS 的。

文件类型

\(\LaTeX{}\)使用过程中,通常需要如下文件:(以及插入的图片文件)

  • .tex 源文件
  • .bib 参考文献

对于高度个性化定制的情形,还需要如下文件:

  • .cls 文档类文件,要求文档类名称和文件名一致
  • .sty 宏包文件,要求宏包名称和文件名一致
  • .bst 参考文献格式模板(Bibtex)
  • .bbx, .cbx 参考文献格式和引用格式模板(Biblatex)

在编译过程中还产生了很多乱七八糟的辅助文件/缓存文件,其中绝大部分都是可以在编译完成后删除的:

  • .aux 交叉引用和标签的辅助文件,可用于下一次编译
  • .log 编译日志,可以用来调试
  • .toc 目录信息文件,用于生成目录
  • .lof 图表信息文件,用于生成图表目录
  • .lot 表格信息文件,用于生成表格目录
  • .out hyperref输出文件,记录书签和超链接等,用于生成PDF
  • .cpt 脚注文件,记录了脚注信息
  • .fdb_latexmk 记录了latexmk在编译过程中生成的文件及其依赖关系
  • .fls 日志文件,记录了编译过程中生成的所有文件,以及它们的依赖关系
  • .xdv XeTex产生的二进制文件,用于转换为PDF
  • .synctex.gz (重要)源文件和PDF之间的双向索引
  • .run.xml 参考文件需要的数据
  • .bbl 参考文献记录文件
  • .blg 参考文献日志
  • .bcf 参考文件相关信息

常见宏包

  • 中文支持
    • ctex: 中文支持宏包
  • 数学相关宏包
    • amsmath: 提供数学环境和命令,是数学排版的基础。
    • amssymb: 提供丰富的数学符号。
    • amsfonts: 包含各种数学字体。
    • amsthm: 支持定义数学定理环境。
    • mathrsfs: 提供特殊的数学花体字母。
  • 数学符号和公式排版宏包
    • bm: 提供在数学中使用粗体命令。
    • mathtools: 对 amsmath 的扩展,增强数学公式排版功能。
  • 图片和图表相关宏包
    • graphicx: 插入图片的核心宏包。
    • caption: 定制浮动体标题。
    • subcaption: 支持在一个浮动体中放置多个子图。
    • tikz: 创建矢量图形。
    • float: 提供更多浮动体位置控制选项。
  • 文档格式和排版相关宏包
    • fancyhdr: 定制页眉页脚。
    • footmisc: 控制脚注样式。
    • titlesec: 定制章节标题格式。
    • titletoc: 定制目录格式。
    • indentfirst: 使每一章节的第一个段落也缩进。
    • geometry: 调整页面布局和页边距。
  • 文档链接、交叉引用和代码块相关宏包
    • hyperref: 添加超链接、交叉引用和书签。
    • cleveref: 提供更智能的交叉引用。
    • listings: 用于插入代码环境。
    • algorithm2e: 用于插入算法环境。
  • 表格相关宏包
    • array: 提供扩展的表格环境。
    • booktabs: 创建高质量表格的命令。
    • longtable: 允许创建跨页的长表格。
    • tabularx: 提供可伸缩的表格环境。
    • multirow,multicol: 创建表格中的多行和多列单元格。
    • threeparttable: 提供表格注释功能。
    • enumitem: 定制列表环境。
  • 其他宏包
    • xcolor: 用于设置颜色。
    • framed: 设置底色。
    • braket: 用于重定义括号。
    • anyfontsize: 允许使用任意大小的字体。
    • nag: 用于检查是否使用了过时的宏包或命令。