程序建表错误

程序建表错误

我正在尝试以编程方式构建一个可变大小的表。所有逻辑都独立于表命令工作,表命令也独立于编程逻辑工作,但不知何故,当我将它们组合在一起时,出现了我无法理解的错误。

我创建了一个最小工作示例,展示了它的工作原理,并删除了我认为无关紧要的所有内容。如下所示,给出了一个示例,说明了如何存储/检索输入数据、表格应该是什么样子以及它挂起的位置:

\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}

在此处输入图片描述

相关内容