\documentclass{ctexart} \usepackage{tabular2} \usepackage{paralist} \usepackage[colorlinks, linkcolor=blue]{hyperref} \usepackage{todo} \ExplSyntaxOn \cs_new:Npn \ttt #1 { \str_set:Ne \l_tmpa_str { \tl_to_str:n {#1} } % 将 #1 转换为字符串 \regex_replace_once:nnN { \s+\Z } {} \l_tmpa_str % 去掉字符串末尾的空白字符 \exp_args:NV \texttt \l_tmpa_str % 输出内容 } \ExplSyntaxOff \begin{document} \title{tabular2 宏包示例文档} \author{Ms\_yam} \date{\today} \maketitle \begin{abstract} 本文档是 tabular2 宏包文档的扩展文档,用于展示 tabular2 的一些基本功能。 同时,本文档也是 tabular2 的功能测试文档。 文档本身只作功能介绍及效果展示,并未直接展示生成表格的相关代码, 需要用户自行查看原代码\footnote{现在编辑器和 PDF 阅读器均支持反向查看,要找对应的源代码几乎无难度。}。 查看原代码之前,应当先阅读 tabular2 宏包文档的用户部分。 \end{abstract} {\small \tableofcontents} \section{行列名设置} \subsection{行与列的名称} 为了便于定位,本宏包的中表格的行与列均可以设置名称。 任意一行或一列可以有多个名称,但一个行名或列名则只能映射到唯一的一行或一列; 然而这种映射却是动态的,如某个行名可以在某个位置指向第 $1$ 行,而在另外一个位置指向第 $2$ 行。 命令 \ttt{\rowname} 与 \ttt{\colname} 专用用来指定行名与列名,它们会自动扩展表格的大小(行数或列数)。 如果您习惯了 \ttt{Excel} 的 \ttt{A1} 样式,则可以通过 \ttt{\excelcolname} 命令来初始化列名 \footnote{它不会影响表格的大小。}。 虽然我们可以使用纯数字\footnote{在内部实现中,所有名称都按凭据表处理(包括纯数字)。}来设置行名与列名, 但这样的名称不能用于定位\footnote{在定位时,会优先尝试将坐标解释为数字坐标,失败后才会按名称查找映射表。}。 因此,除非要设置表头,否则建议使用字母来设置行名与列名。 \subsection{表头与行列名} 表格有行表头与列表头;默认以行名为行表头;以列名为列表头。 如果某一个行设置了多个行名,则以最后一个行名为准;列表头类似。 当显示指定行表头或列表头时,则不受行列名的影响。 默认情况下,只输出列表头,不输出行表头。 表头是否输出则可通过相关设置来调整。\todo{更新如何设置表头是否输出;} \subsection{示例} 由于宏包内部使用两种完全不同的输出方式,为保证测试的覆盖程度, 本文档中的所有输出示例,默认均以全边框形式及三线表形式两种方式输出。 以下是第一个示例,用于观察行名与列名设置效果:(包含行列表头) \begin{xtable}[rowheader=true] \excelcolname \colname (3) { AA, BB, CC } \colname {5} \rowname [|] { 2 | A } \cell (2,5) { data } \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 说明: \begin{compactitem} \item 此时行名的映射为:\ttt{<2>} = $1$(无效),\ttt{} = $2$; 如果这时输入行坐标 $2$,它会识别为第 $2$ 行而非第 $1$ 行; \item 对于列名同理,虽然列名 \ttt{<5>} = $1$,但因其不生效,所以最终修改的是第 $5$ 列; \item 行列名中所有字符均会被当作字符串处理,如 \ttt{\footnote} 等; \item 对于表头来说,以上设置却是有生效的;\footnote{脚注等命令,需要通过显示设置行列表头才生效。} \end{compactitem} \section{数据录入环境} \ttt{data} 环境是主要的数据输入环境。目前该环境支持标准输入、CSV输入及JSON输入三种输入方式。 同时,CSV与JSON还可以考虑支持文件输入。\todo{解决文件输入;} \subsection{标准输入} 标准输入是本宏包设计的主要输入方式。 该输入方式采用硬解码,处理速度有较明显优势,且直接支持行列表头输入,应当作为常规表格的首选输入方式。 \subsubsection{默认效果} 以下是全部使用默认值(逗号分隔,\ttt{\\} 换行)的标准输入的效果:\par \begin{xtable} \begin{data} Name, Sex, Age\footnote{这是一条演示用的脚注。}\\ John, man, 18\\ Leon, , 20\\ \\ Lily, woman, 21\\ ,\\ \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 其中:首行为表头(兼列名),中间的行会保留,尾随的空行不会。 如果某行在某列之后无需设置,则允许省略该行的后续分隔符。 \subsubsection{特殊字符} 标准输入不对特殊字符进行任何预处理,所有输入均为凭据表,直接由 \TeX 的默认方式处理。 但由于 “\ttt{\\}” 用于分隔表格行,因此单元格换行需要使用 “\ttt{\newline}”。 如果单元格本身带逗号,则可通过指定其它分隔符(选项 “\ttt{sep}” )来规避。\par \begin{xtable} \begin{data}[sep={=}] AA = BB = CC \\ A\{[\#\$ = a\newline b = "\_ \\ B\}]\%\& = c\\d = ,\textbackslash\\ \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \subsection{CSV 输入} CSV输入与标准输入非常相似,但是它会处理特殊字符\footnote{目的是尽量匹配 CSV 的输入语法。}; 代价则是处理速度会更慢。 在没有特殊字符的情况下,应当尽量使用标准输入。 \subsubsection{默认效果} 通过指定 “\ttt{format=csv}” 选项(或直接使用 “\ttt{csv}” ),可让本环境按 CSV 格式处理输入。\par \begin{xtable} \begin{data}[csv] AA , BB , CC\footnote{} \\ A , ab , 1 \\ B , cd , 2 \\ \\ , , 3\footnote{暂时只有内容才支持脚注。} \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 虽然本宏包也支持指定分隔符,但是仍建议遵守约定,使用默认值 “\ttt{,}”。 \subsubsection{特殊字符【待处理】} \todo{处理CSV中的特殊字符} \subsection{JSON 输入} JSON 的输入方式与标准输入迥异,不需要使用 “\ttt{\\}” 来换行。 其属性名为列名,属性值为表体。 \subsubsection{默认效果} 通过指定 “\ttt{format}” 选项为 “\ttt{json}”,可让本环境处理 JSON 格式。\par \begin{xtable} \begin{data}[format=json] [ { "A" : "a", "B" : true, "C" : 1 }, { "A" : "bc", "C" : 2 }, { "A" : "d", "C" : 3, "D\footnote{}" : "不支持 TeX 命令" }, {}, { "A" : "e", "B" : false, "C" : 4 } ] \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \subsubsection{特殊字符【待处理】} \todo{处理JSON中的特殊字符} \subsection{输入位置} 可以通过 “\ttt{loc}” 选项来指定输入的起点位置 \footnote{这可能会造成位置之前的列没有列名,在这种情况下其表头空。}; 如果未指定,则默认为“\{1, 1\}”。 对于标准输入(含 CSV 格式),输入过程中,会根据输入列名依次更新列名映射。 如本例中的 “\ttt{Name}”,它原本映射到第 $1$ 列,但输入后映射到第 $3$ 列 \footnote{虽然映射更新了,但它不会影响之前的录入,如单元格 “\ttt{(1,1)}”。}。 \begin{xtable} \rowname{Name} \cell(1,Name){Old} \begin{data}[loc={2,3}] Name, Sex, Age\\ John, man, 18\\ Leon, , 20\\ Lily, woman, 21\\ \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 但对于 JSON 格式,则是完全不一样的逻辑: 如果列名已经存在,则直接填充数据;如果列名不存在,则在指定位置及之后依次添加新列名。 \footnote{JSON 中的属性名可以是无序的,所以列名顺序设计上是独立的;而 CSV 有序,因此会自动更新表头。} \begin{xtable} \begin{data} Sex, Name\\ man, John \end{data} \begin{data}[loc={2,3}, format=json] [ { "Name": "John", "Sex": "man", "Age": 18 }, { "Name": "Leon", "Sex": "", "Age": 20 }, { "Name": "Lily", "Sex": "woman", "Age": 21 }, ] \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \subsection{无表头输入} 在标准输入与 CSV 输入中,默认第一行为表头兼列名; 但这可能通过将 “\ttt{header}” 选项设为 “\ttt{false}” 来将第一行当作数据行处理。 \begin{xtable} \excelcolname \begin{data}[header=false] Name, Sex, Age\\ John, man, 18\\ Leon, , 20\\ Lily, woman, 21\\ \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 如果同时还需要将表格设置为无表头,则需要在 \ttt{xtable} 层级中设置 \footnote{此时,\ttt{data} 层级默认会继承这个设置,除非手动指定。}。 \begin{xtable}[header=false] \begin{data} Name, Sex, Age\\ John, man, 18\\ Leon, , 20\\ Lily, woman, 21\\ \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 如果即想把第一行当作列名又想不输出表头,则需要组合设置该选项。 \begin{xtable}[header=false] \begin{data}[header=true] Name, Sex, Age\\ John, man, 18\\ Leon, , 20\\ Lily, woman, 21\\ \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 对于JSON格式,由于属性名始终为列名,因此在 \ttt{data} 层级不支持这个选项。 但在 \ttt{xtable} 层级中,仍然支持。 \begin{xtable}[header=false] \begin{data}[format=json] [ { "Name": "John", "Sex": "man", "Age": 18 }, { "Name": "Leon", "Sex": "", "Age": 20 }, { "Name": "Lily", "Sex": "woman", "Age": 21 }, ] \end{data} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \subsection{文件导入【待实现】} \ttt{\file} 是的功能与 \ttt{data} 的功能几乎一致,除了其是以文件作为输入及换行有特殊处理。 \todo{实现文件导入功能} \section{行列与单元格输入} 本宏包支持按行、按列及按单元格输入,且这三种方式可以组合使用。 输入过程中如果数据超出现有行列数,则会自动添加行列。 此部分是本宏包与传统表格之间的最大差异点之一。 \subsection{按行输入} 按行输入(命令 \ttt{\row})用于横向添加数据,可以指定起点位置,默认为新行第一列。以下是按行输入的示例: \begin{xtable} \begin{data} Name, Sex, Age\\ John, man, 18\\ \end{data} \row[|]{Lily||20} \row(4){Jacob, man, 21} \row(3,2){woman, 18, newcol} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \subsection{按列输入} 按行输入(命令 \ttt{\col})用于纵向添加数据,可以指定起点位置,默认为新列第一行。以下是按列输入的示例: \begin{xtable} \begin{data} Name, Sex, Age\\ John, man, 18\\ \end{data} \col(newcol)[|]{A|B} \col{1,2} \col(2,Sex){woman, man} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \subsection{按单元格输入} 按单元格输入(命令 \ttt{\cell})用于向指定位置添加数据。以下是按单元格输入的示例: \begin{xtable} \begin{data} Name, Sex, Age\\ John, man, 18\\ \end{data} \cell(3,newcol){newdata} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \section{保存与加载} 为了提高数据复用率,本宏包提供了表格保存与加载功能。 \subsection{保存表格} 以下是一个基础表,使用保存命令 \ttt{\savetable},然后再修改了部分内容。(保存数据没有直接体现) \begin{xtable} \begin{data}[format=json] [ { "Name": "John", "Sex": "man", "Age": 18 }, { "Name": "Leon", "Sex": "", "Age": 20 }, { "Name": "Lily", "Sex": "woman", "Age": 21 }, ] \end{data} \savetable{abc} % 注意保存的节点 \cell(2,Name){Unsaved} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 请注意,在保存命令之后做的修改不会影响已经保存的表格。 \subsection{加载表格} 以下是复用的表格数据: \begin{xtable} \col(Name){A,B,C,D} % 被 \loadtable 覆盖 \loadtable{abc} \cell(2,Sex){man} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 注,加载表格会覆盖之前的设置,因此通常把它放置到第一行。 \section{格式设置} \subsection{宽度与高度} 表格会依次计算各列所需的宽度,然后再计算各行所需的高度 \footnote{这里所说的高度是行的最顶端面到底端的距离,实现中包括 \LaTeX 中的高度与深度两个值。}, 以包容所有单元格。 \begin{xtable} \begin{data} AA, BB, CC, EE\\ abcde, 12, dd, abccba\\ ab, 12, xy, abc\\ \end{data} \cell(2,BB){19\\20} \savetable{abc} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 但可以通过 \ttt{\rowheight} 与 \ttt{\colwidth} 来指定额外的规则或固定尺寸。 \begin{xtable} \loadtable{abc} \rowheight[same]{auto} \colwidth[auto][0.45\textwidth]{same,same,fill,1em} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 注:如果宽度设置过小,会导致数据超出单元格。\todo{如果盒子高度过小,会怎么样。} \subsection{对齐方式} 表格默认是左右居中,上下底对齐的; 也可通用 \ttt{\rowalign} 与 \ttt{\colalign} 来指定对齐方式。 \begin{xtable} \loadtable{abc} \rowheight[same]{auto} \rowalign[b]{b,m,m} \colalign{l,c,c,r} \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par \section{合并单元格} \TeX{} 应当避免使用合并单元格,但为了满足某些需求,本宏包提供了合并单元格的功能。 \begin{xtable} \begin{data} Name, Sex, Age, remark\\ John, man, 18, test\\ John, , , test\\ John, , , test\\ John, , , test\\ John, man, 18, test\\ \end{data} \cell(2,Sex){man\\18\footnote{这是一个合并单元格。}} \mergecell(2,Sex)(4,Age)[br] \end{xtable} \rendertable [border] \rule{2em}{0pt} \rendertable [booktabs] \par 合并单元格的齐还需要进一步研究。\todo{优化合并单元格的对齐。} \section{渲染输出} 目前支持四种样式的输出: \begin{compactitem} \item 直接按行打印内容(纯盒子); \item 三线表(如上述示例中右边的效果);; \item 栅格模式(不支持合并单元格); \item 全边框模式(如上述示例中左边的效果); \end{compactitem} \subsection{直接打印} 可以使用 \ttt{\printtable} 直接打印表格。 每行数据使用一个水平盒子输出,且不绘制任何边框。因此它可以自动换页,其效果如下: \printtable*[2em] \subsection{三线表} 由于三线表在 \TeX{} 中比较受欢迎,因此本宏包添加了支持。 除了传统的三条线外,本宏包还支持添加额外的水平分隔线,效果如下: \rendertable [booktabs, rule={1,4}] \par \subsection{栅格模式} 本渲染模式下,允许用户指定要绘制哪些水平线与垂直线,但它只支持整条线。其效果如下: \rendertable [grid, rule={ \hrule{0.7pt,midrule,1=dash,4=bottomrule}, \vrule{0.7pt,3=dotted} }] \par \subsection{全边框模式} 本模板会输出所有边框,包括合并单元格的边框。示例在前面已经讲了,这里就不举例了。 \todos \end{document}