LaTeX 如何减少重复代码?使用自定义命令、环境与 \input
在 LaTeX 项目中减少重复代码,可以从三个方面入手:用自定义命令复用相同格式,用环境复用固定的内容结构,再用 \input 管理多个文件共用的代码。并不是所有重复内容都值得封装,建议优先处理出现多次、写法一致且后续可能一起修改的部分。
同一格式反复手写时:定义带参数的命令
下面这份源码可以直接编译,\vect、\code、\R 各定义一次,正文反复调用:
\documentclass[11pt]{article}
\usepackage{amsmath,amssymb}
\newcommand{\vect}[1]{\boldsymbol{#1}}
\newcommand{\code}[1]{\texttt{#1}}
\newcommand{\R}{\mathbb{R}}
\begin{document}
For $\vect{x}\in\R^d$, open \code{main.tex}.
\end{document}
定义写在 \begin{document} 之前,全文都能调用;写在正文中,只有它之后的内容能用。命令名与已有宏包撞车时会报 ! LaTeX Error: Command \R already defined.,换名即可;要覆盖已有定义时用 \renewcommand,仅在命令未定义时提供默认值可用 \providecommand。
\newcommand 最多接受 9 个参数;参数到四五个时,调用处要对着定义才能看懂。
同一结构反复出现时:定义环境
论文里几十个格式相同的表格适合抽成一个环境。下面的 resulttable 接受列格式和表头行两个参数:
\documentclass[11pt]{article}
\usepackage{booktabs}
\newenvironment{resulttable}[2]{%
\begin{table}[htbp]\centering
\begin{tabular}{#1}\toprule
#2\\\midrule
}{%
\bottomrule\end{tabular}
\end{table}
}
\begin{document}
\begin{resulttable}{lcc}{Model & Accuracy & F1}
Baseline & 0.812 & 0.794 \\
Ours & 0.867 & 0.851 \\
\end{resulttable}
\end{document}
之后每张表只写数据行,\toprule、列格式、浮动体位置都由环境提供。
环境体内部出错时,日志报的行号是展开之后的位置,与源码行号对不上;这时先把这段定义和一个最小调用单独放进测试文件编译,定位到具体行再放回主文档。
多个文件共用片段时:拆出公共文件
同一段导言区被几个文件各抄一份时,用 \input 解决。
preamble.tex:
\usepackage{amsmath,amssymb}
\newcommand{\vect}[1]{\boldsymbol{#1}}
main.tex:
\documentclass{article}
\input{preamble}
\begin{document}
$\vect{x}$
\end{document}
\input 是纯插入,本例把 main.tex 放在项目根目录,路径以编译时的项目根目录为基准,而不是写这行 \input 的章节文件位置;在 chapters/intro.tex 里写 \input{intro2} 会报文件找不到,要写成相对主文件的 chapters/intro2。
章节级拆分用 \include 更合适:前后自动 \clearpage,每章生成独立的 .aux,配合 \includeonly 可以只编译改动的章节;\include 不能嵌套。
封装之前先确认:三类片段才值得收敛
封装有成本,三条同时满足才动手:出现三次以上、每次内容一致(而不只是看起来相似)、以后会一起改。
只出现两次的段落封装之后,读者要跳到另一个文件才能看懂;各处有细微差异的片段强行统一,要加一排开关参数,调用处比原文更难读。
改完之后:编译并复核关键位置
编译一次,核对三处:定义文件是否在 \begin{document} 之前被引入、\input 路径是否相对主文件书写、公式与表格的编号与交叉引用是否仍指向原位。
| 报错 | 触发原因 | 处理 |
|---|---|---|
! LaTeX Error: Command \foo already defined. | 命令或环境使用了已存在的名字 | 换名;确认要覆盖时用 \renewcommand |
| ! LaTeX Error: Environment foo undefined. | 环境定义在被调用之后,或定义所在文件没有被执行到 | 把定义移到导言区,检查 \input 是否被引入 |
| ! LaTeX Error: File 'chapters/intro2.tex' not found. | \input 路径按当前文件写,而解析以主文件目录为基准 | 改成相对主文件的路径 |
| 日志行号与源码对不上 | 命令体或环境体展开后报的位置 | 单独建一个只含定义与调用的小文件编译,定位到具体行 |
总结
-
格式收进命令:
\newcommand一次定义,正文反复调用; -
结构收进环境:表格、定理框这类骨架用
\newenvironment封装; -
跨文件收进公共文件:
\input摘导言区,\include拆章节; -
先判断再封装:三条标准同时满足才动手。
把主文件和各章节一起导入 EasyLaTeX 编辑器,编译入口按 main.tex 设置。