![程序建表错误](https://linux22.com/image/334285/%E7%A8%8B%E5%BA%8F%E5%BB%BA%E8%A1%A8%E9%94%99%E8%AF%AF.png)
我正在尝试以编程方式构建一个可变大小的表。所有逻辑都独立于表命令工作,表命令也独立于编程逻辑工作,但不知何故,当我将它们组合在一起时,出现了我无法理解的错误。
我创建了一个最小工作示例,展示了它的工作原理,并删除了我认为无关紧要的所有内容。如下所示,给出了一个示例,说明了如何存储/检索输入数据、表格应该是什么样子以及它挂起的位置:
\documentclass{article}
\usepackage{tabularx}
\newcount\tmpnum \newcounter{tmpind} \newcounter{basesize}
\setcounter{tmpind}{0} \setcounter{basesize}{15} %% for 5 lines of three columns in empty table; table should expand if data count exceeds this size
\newif\iftestEmptyBool \newcommand{\testEmpty}[1]{\setbox0=\hbox{#1}\ifdim\wd0=0pt \testEmptyBooltrue\else \testEmptyBoolfalse\fi}
\def\storedata#1#2{\tmpnum=0 \edef\tmp{\string#1}\storedataA#2\end\expandafter\def\csname data:\tmp:0\endcsname{\tmpcnt}}
\def\storedataA#1{\advance\tmpnum by1
\ifx\end#1\else
\expandafter\def\csname data:\tmp:\the\tmpnum\endcsname{#1}%
\expandafter\storedataA\fi
}
\def\getdata[#1]#2{\csname data:\string#2:#1\endcsname}
\def\funcOne{\addtocounter{tmpind}{1}\testEmpty{\getdata[\thetmpind]\myData}\iftestEmptyBool\else\funcOne\fi}
\def\funcTwo{
\ifnum\the\value{tmpind}>0
\ifnum\the\value{tmpind}<\the\value{basesize}\fi%&&\\ \large - & \large - & \large - \\ \hline\fi%
\ifnum\the\value{tmpind}=\the\value{basesize}\addtocounter{tmpind}{-3} \fi%&&\\ \getdata[\thetmpind-2]\myData & \getdata[\thetmpind-1]\myData & \getdata[\thetmpind]\myData \\ \hline\fi%
\addtocounter{basesize}{-3}
\funcTwo
\fi
}
\newcommand{\buildTable}{\funcOne\addtocounter{tmpind}{-1}\begin{tabularx}{\linewidth}{|c|c|X|c|}\hline Column 1 & Column2 & Column3\\&&\\ \hline\funcTwo\end{tabularx}}
\begin{document}
\storedata\myData{{data1}{data2}{data3}{data4}{data5}{data6}}\funcOne\addtocounter{tmpind}{-1}The number of stored items is \thetmpind.
\vspace{10pt}Example of how it should look:
\begin{tabularx}{\linewidth}{|c|c|X|c|} \hline
Column 1 & Column2 & Column3\\ &&\\ \hline
&&\\ \large - & \large - & \large - \\ \hline
&&\\ \large - & \large - & \large - \\ \hline
&&\\ \large - & \large - & \large - \\ \hline
&&\\ \getdata[4]\myData & \getdata[5]\myData & \getdata[6]\myData \\ \hline
&&\\ \getdata[1]\myData & \getdata[2]\myData & \getdata[3]\myData \\ \hline
\end{tabularx}
\vspace{10pt}How it does look:
\buildTable
\end{document}
可以通过删除这些行中活动代码末尾的 来放回 中两\ifnum
行末尾的注释部分,以重现该错误。\funcTwo
\fi%
如果有人知道为什么会发生这种情况以及如何解决它,那就太棒了!:)
答案1
如果其他人也遇到类似的问题,我会发布我找到的解决方案(尽管这表明我缺乏对一些简单问题的关键理解):
在我的例子中,我有一个拼写正确的表格,显示了我想要的内容:
\vspace{10pt}Example of how it should look:
\begin{tabularx}{\linewidth}{|c|c|X|c|} \hline
Column 1 & Column2 & Column3\\ &&\\ \hline
&&\\ \large - & \large - & \large - \\ \hline
&&\\ \large - & \large - & \large - \\ \hline
&&\\ \large - & \large - & \large - \\ \hline
&&\\ \getdata[4]\myData & \getdata[5]\myData & \getdata[6]\myData \\ \hline
&&\\ \getdata[1]\myData & \getdata[2]\myData & \getdata[3]\myData \\ \hline
\end{tabularx}
在此表中,\getdata[?]\mydata
命令硬引用特定的计数器/索引值。
在我的\buildTable
命令中,我使用了一个\funcTwo
尝试使用相对索引的函数:
\def\funcTwo{
\ifnum\the\value{tmpind}>0
\ifnum\the\value{tmpind}<\the\value{basesize} &&\\ \large - & \large - & \large - \\ \hline\fi%
\ifnum\the\value{tmpind}=\the\value{basesize}\addtocounter{tmpind}{-3} &&\\ \getdata[\thetmpind-2]\myData & \getdata[\thetmpind-1]\myData & \getdata[\thetmpind]\myData \\ \hline\fi%
\addtocounter{basesize}{-3}
\funcTwo
\fi
}
显然你不能在 tex/latex 中做到这一点(考虑到我读过的一些内容,这是有道理的,但我以前没有有意识地考虑过这一点)。通过用详细调用替换相对引用\addtocounter
,我实现了相同的效果。
\def\funcTwo{
\ifnum\the\value{tmpind}>0
\ifnum\the\value{tmpind}<\the\value{basesize}\addtocounter{basesize}{-3}\emptyRow\fi
\ifnum\the\value{tmpind}=\the\value{basesize}\addtocounter{basesize}{-3}\filledRow\fi
\funcTwo
\fi}
\newcommand{\emptyRow}{%
&&\\ \large - & \large - & \large - \\ \hline}
\newcommand{\filledRow}{%
&&\\ \addtocounter{tmpind}{-2}\getdata[\thetmpind]\myData
& \addtocounter{tmpind}{1}\getdata[\thetmpind]\myData
& \addtocounter{tmpind}{1}\getdata[\thetmpind]\myData
\addtocounter{tmpind}{-3} \\ \hline}
这会产生与硬编码表相同的结果,但会根据现有数据量进行调整。:)
答案2
这是一个常见的问题:一个条件不能跨越两个(或更多)对齐单元。
这是一个更简单的实现xparse
:
\documentclass{article}
\usepackage{xparse}
\usepackage{tabularx}
\newcounter{basesize}
\setcounter{basesize}{15}
\ExplSyntaxOn
% \storedata{<name>}{item1,item2,...}
\NewDocumentCommand{\storedata}{mm}
{
\seq_clear_new:c { l_cooper_data_#1_seq }
\seq_set_from_clist:cn { l_cooper_data_#1_seq } { #2 }
}
% \buildTable{<name>}
\NewDocumentCommand{\buildTable}{m}
{
\cooper_buildtable:n { #1 }
}
% variables
\seq_new:N \l_cooper_reverse_seq
\tl_new:N \l_cooper_tablebody_tl
\int_new:N \l_cooper_column_int
% internal function
\cs_new_protected:Nn \cooper_buildtable:n
{
% use a temporary sequence
\seq_set_eq:Nc \l_cooper_reverse_seq { l_cooper_data_#1_seq }
% if it has less elements than stated in basesize fill with `--`
\int_compare:nT { \seq_count:c { l_cooper_data_#1_seq } < \value{basesize} }
{
\prg_replicate:nn { \value{basesize} - \seq_count:c { l_cooper_data_#1_seq } }
{
\seq_put_right:Nn \l_cooper_reverse_seq { -- }
}
}
% reverse the sequence
\seq_reverse:N \l_cooper_reverse_seq
% start preparing the body
\tl_clear:N \l_cooper_tablebody_tl
\int_zero:N \l_cooper_column_int
% fill three rows and then go to a new one
\seq_map_inline:Nn \l_cooper_reverse_seq
{
\int_compare:nT { \l_cooper_column_int = 0 }
{
\tl_put_right:Nn \l_cooper_tablebody_tl { && \\ }
}
\int_incr:N \l_cooper_column_int
\int_compare:nTF { \l_cooper_column_int = 3 }
{
\tl_put_right:Nn \l_cooper_tablebody_tl { ##1 \\\hline }
\int_zero:N \l_cooper_column_int
}
{
\tl_put_right:Nn \l_cooper_tablebody_tl { ##1 & }
}
}
% make the table
\begin{tabularx}{\linewidth}{|c|c|X|}
\hline
Column 1 & Column2 & Column3 \\ &&\\
\hline
\tl_use:N \l_cooper_tablebody_tl
\end{tabularx}
}
\ExplSyntaxOff
\begin{document}
\storedata{myData}{data1,data2,data3,data4,data5,data6}
\noindent
\buildTable{myData}
\end{document}