如果表格内容已经作为 .csv 文件等 外部数据 存在,就不必逐个单元格手动重打。LaTeX 有多个包可以读取 CSV 并转换成表格,因此数据变化时不需要改写源文件。本页介绍三种工具及其适用场景:快速的 csvsimple、擅长格式化的 pgfplotstable,以及数据库式的 datatool。最后还会提到 siunitx 的 S 列,用于 按小数点对齐数字(S 列的完整说明见“单位(siunitx)”页面)。
为什么从数据生成表格
实验结果和汇总表几乎总是从电子表格或仪器中以 CSV(逗号分隔值) 的形式导出。手工把它们复制到 tabular 单元格里既枯燥又容易出错;每增加一行、每改动一个数字,都意味着还要再编辑一次稿件。
换一种思路:把数据留在数据文件中,只告诉 LaTeX 去读取并排版它。 这样只要更新数据并重新编译,表格就会随之更新。有一个源 CSV,就能在正文、幻灯片和附录中反复使用同一组数字,也不会产生转录错误。这种“数据与表现分离”的做法,与 LaTeX 区分逻辑结构和外观的思想是一致的。
本页示例使用下面这个小 CSV 文件。第一行是 标题行(表头),列名为 product、price、weight;后面的行才是数据。
product,price,weight
Apple,380,182.5
Orange,120,95.0
Melon,1280,1450.2快速读取 — csvsimple
csvsimple 是一个轻量包,用来读取 CSV 并生成表格或循环。用 \usepackage{csvsimple} 载入它(当前版本内部会选择 LaTeX3 实现 csvsimple-l3)。最快的入口是 \csvautotabular{data.csv}:只给出文件名,它就会自动把整个 CSV 放进一个 tabular,并把第一行设为带横线的表头。它适合快速查看数据内容。
\csvautotabular{data.csv}这一行会生成一个三列三行的表格,表头为 product、price、weight。它很方便,但格式控制有限。如果想自己决定对齐方式、横线以及保留哪些列,就使用 \csvreader,这才是 csvsimple 的主力命令。
\csvreader 采用 \csvreader[options]{data.csv}{assignments}{body} 这样的三个引数。第二个引数 是要读取的文件,第三个 把列名绑定到宏,第四个 是每一行要输出的内容。例如写 price=\price,就能在主体中用 \price 取得 price 列的值。表格外框通过 tabular=、table head=(标题行)等选项给出。
\csvreader[
tabular = l r r,
table head = \hline Product & Price & Weight \\ \hline,
late after line = \\]
{data.csv}
{product=\product, price=\price, weight=\weight}
{\product & \price & \weight}这里用 tabular = l r r 声明三列(“左、右、右”),用 table head 放置标题行和顶端横线,主体 {\product & \price & \weight} 将每个数据行展开为单元格。late after line = \\ 告诉 csvsimple 在每一行后追加行结束符 \\,这是只在行与行之间放置换行、而不在最后一行后留下多余换行的惯用写法。如果表头名包含空格或符号,也可以在第三个引数中按列号访问:\csvcoli、\csvcolii、\csvcoliii … 分别表示 第一、第二、第三 列的内容。
默认情况下,第一行会被当作 表头,不包含在数据中。读取没有表头行的 CSV 时,带星号的 \csvreader* 会把第一行也作为数据读取。csvsimple 还提供 filter 按条件筛选行,以及 \csvstyle / \csvnames 复用一组列分配等功能,这些功能也能用于表格之外的一般逐行处理。
读取并格式化 — pgfplotstable
如果想精细控制数字的 显示方式,pgfplotstable 是最强大的选择。它属于 pgfplots,用 \usepackage{pgfplotstable} 载入。核心命令只有一个:\pgfplotstabletypeset[options]{data.csv}。它读取 CSV,按指定精度和数字样式格式化,并在内部组装一个 tabular 输出。读取 CSV 时要用 col sep=comma 声明分隔符。
所有行为都通过 键值选项 控制。下面列出最重要的选项。
| 选项 | 作用 | |
|---|---|---|
col sep=comma | col sep=comma | 按 CSV(逗号分隔)读取;默认是空白分隔 |
header | header=has colnames / header=false | 把第 1 行当作列名 / 当作没有表头 |
columns | columns={a,b,...} | 选择要输出的列及其顺序 |
columns/NAME/.style | columns/price/.style={...} | 只给某个命名列应用格式 |
column name | column name=标题 | 替换该列打印出的标题 |
fixed | fixed, fixed zerofill, precision=n | 定点格式、末尾补零、小数位数 n |
sci | sci, sci zerofill | 按科学记数法(指数形式)排版 |
string type | string type | 文本列(不应用数字格式化) |
dec sep align | dec sep align | 按小数点对齐该列(需要 array) |
\pgfplotstabletypeset[
col sep = comma,
header = has colnames,
columns = {product, price, weight},
columns/product/.style = {string type, column name = Product},
columns/price/.style = {column name = Price, fixed, precision = 0},
columns/weight/.style = {column name = Weight (g), fixed, fixed zerofill,
precision = 1, dec sep align},
]{data.csv}在这个例子中,product 列设为 string type(文本),price 列设为整数(precision=0),weight 列设为一位小数并补尾随零,再用 dec sep align 按小数点对齐。表头则分别用 column name 替换。同一份数据只要改变 precision,显示位数就会改变;能够独立于 CSV 控制数字外观,正是 pgfplotstable 的强项。
pgfplotstable 还能从读取的列派生 计算列:可以用 create on use 定义“使用时计算”的列,也可以在 columns/.../.style 中通过 postproc cell content 做后处理;类似电子表格的工作可以全部在 LaTeX 内完成。横线方面可用 every head row/.style 或与 booktabs 联动(自动插入 \toprule / \midrule / \bottomrule 的设置)来调整。功能越强,语法也越重,因此一个经验法则是:复杂数值表用 pgfplotstable,朴素的 CSV → 表格用 csvsimple。
作为数据库处理 — datatool
第三个包 datatool 会把 CSV 作为 数据库 读取,并擅长逐行处理(类似邮件合并)。用 \usepackage{datatool} 载入后,先用 \DTLloaddb{name}{data.csv} 把 CSV 载入一个有名字的数据库。默认第一行是表头,其列名会成为每个值的 键。没有表头的 CSV 可写 \DTLloaddb[noheader]{...}{...},列会自动命名为 Column1、Column2 …。
载入之后,用 \DTLforeach{name}{assignments}{body} 逐行遍历。分配写成“宏 = 列名”,例如 \DTLforeach{db}{\Product=product,\Price=price}{…},在主体中 \Product 和 \Price 会展开为该行的值。要生成表格,就在 tabular 中运行 \DTLforeach,并在主体末尾放置行结束符 \\。
\DTLloaddb{goods}{data.csv}
\begin{tabular}{l r}
\hline
Product & Price \\
\hline
\DTLforeach{goods}{\Product=product, \Price=price}{%
\Product & \Price \\}
\hline
\end{tabular}这里把 CSV 载入为 goods,并在 tabular 中让 \DTLforeach 为每一行输出“商品名 & 价格”。datatool 真正的强项不是单纯排表,而是 数据操作:可以用宏求和、求平均、排序、按条件排除行,也常用于生成文献列表和合并文档。反过来,如果只是把 CSV 变成表格,csvsimple 更简洁。
按小数点对齐数字 — siunitx 的 S 列
无论数据是否来自 CSV,数字列都有一个共同问题:如果位数不对齐就很难阅读。在手写的 tabular 中解决这个问题的标准做法,是使用 siunitx 的 S 列。在列指定中用 S 代替 r 等,该列数字就会 按小数点位置对齐。载入 \usepackage{siunitx} 后即可使用。
\begin{tabular}{l S[table-format=4.1]}
\toprule
{Product} & {Weight / \unit{\gram}} \\
\midrule
Apple & 182.5 \\
Orange & 95.0 \\
Melon & 1450.2 \\
\bottomrule
\end{tabular}这里第二列写成 S[table-format=4.1],表示“整数 4 位、小数 1 位”,从而把 182.5、95.0、1450.2 按小数点对齐。这里有 两个要点。第一,table-format=整数位.小数位 要 按该列中的最大值 指定。第二,列标题等文本要用花括号 {…} 包起来保护({Weight / \unit{\gram}})。如果忘了保护,siunitx 会试图把标题当作数字读取,对齐就会失效。
S 列的更完整用法,包括指定 table-format、保护文本、可在 \multicolumn 中使用的宏形式 \tablenum,以及带指数的数值处理,都在“单位(siunitx)”页面中说明。把职责分开,正文中的量用 \qty,表中的数字用 S 列,就能让整篇文档的数字样式保持一致。
该用哪一个
最好的做法是按目的选择。粗略指南如下。
- 朴素的 CSV → 表格: 用
csvsimple。\csvautotabular可快速生成,\csvreader可控制对齐和横线。 - 精细控制位数、数字样式或需要计算列: 用
pgfplotstable。它最强大,但语法也较重。 - 主要目标是数据操作,例如求和、排序、条件处理:用
datatool。合并文档也适合。 - 只是想让一列数字按小数点对齐: 用
siunitx的S列。可以直接放进手写的tabular。
无论采用哪种方法,基础都是同一套 tabular 词汇:列指定、&、\\ 和横线。先掌握“tabular 基本”,再根据数据量和格式需求选择工具会更稳妥。