我想定义适当的列类型来抑制整个排表格全部的列(除标题列,即第一列外)为空。即,内容tabular
如下:
Label 1 & 62 & 79 \\
Label 2 & & \\
Label 3 & & 31 \\
Label 4 & 45 & \\
我想自动抑制带有 的行Label 2
。
我的尝试:
我定义了一个T
列类型,此时确定前一行是否要通过以下方式排版:
\newcommand{\TitleColumn}[1]{% We are starting a new row
%% If there was a previous row that needed to be output, display that now
\iftoggle{DisplayThisRow}{%
\PrintTableTokens% Print prior row
\global\togglefalse{DisplayThisRow}% Assume entire row is empty
}{%
%\vspace*{-\baselineskip}% Attempt to fix empty rows.
}%
\ResetTableTokens%
\AddTableTokens{#1}% Start a new row with the row label
}
所有其他列的类型为在遇到非空单元格时L
将布尔值设置DisplayThisRow
为:true
\newcommand{\ColumnL}[1]{%
\AddTableTokens{#1}% <--- Need a leading & here
\IfStrEq{#1}{}{}{% Enable printing of row if non-empty content encoutered
\global\toggletrue{DisplayThisRow}%
}%
}
我的尝试基于
得出
可能不是最好的方法。目前存在的问题包括:
当需要抑制某一行时,会输出空白。
\AddTableTokens{& #1}
缺少列分隔符。在宏的调用中包含列分隔符\ColumnL
会导致对齐制表符 & 位置错误。
我原本以为会出现一个问题,即由于没有后续
T
列,因此不会打印最后一行,但由于某些奇怪的原因,最后一行Label 4
却被首先打印!
代码:
\documentclass{article}
\usepackage{collcell}
\usepackage{tabularx}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{showframe}
%% This is based on:
%% https://tex.stackexchange.com/q/165126/4301
%% https://tex.stackexchange.com/q/175568/4301
%%
\makeatletter
\newcommand*{\@MyTempTableTokens}{}%
\newtoks\@tabtoks
%%% assignments to \@tabtoks must be global, in case they are done in \foreach
\newcommand\AddTableTokens[1]{\global\@tabtoks\expandafter{\the\@tabtoks#1}}
\newcommand\eAddTableTokens[1]{% Do NOT add a tailing \\ for each line
\protected@edef\@MyTempTableTokens{#1}%
\expandafter\AddTableTokens\expandafter{\@MyTempTableTokens \\}%
}%
%%% variable should be operated on always locally or always globally
\newcommand*\ResetTableTokens{\global\@tabtoks{}}
\newcommand*\PrintTableTokens{\the\@tabtoks}
\makeatother
\newcommand{\ColumnL}[1]{%
\AddTableTokens{#1}% <--- Need a leading & here
\IfStrEq{#1}{}{}{% Enable printing of row if non-empty content encoutered
\global\toggletrue{DisplayThisRow}%
}%
}
\newtoggle{DisplayThisRow}%
\togglefalse{DisplayThisRow}%
\newcommand{\TitleColumn}[1]{% We are starting a new row
%% If there was a previous row that needed to be output, display that now
\iftoggle{DisplayThisRow}{%
\PrintTableTokens% Print prior row
\global\togglefalse{DisplayThisRow}% Assume entire row is empty
}{%
%\vspace*{-\baselineskip}% Attempt to fix empty rows.
}%
\ResetTableTokens%
\AddTableTokens{#1}% Start a new row with the row label
}
\newcolumntype{L}{>{\collectcell\ColumnL}l<{\endcollectcell}}
\newcolumntype{T}{>{\collectcell\TitleColumn}X<{\endcollectcell}}
\begin{document}
%\showcols
\noindent
\begin{tabularx}{\linewidth}{@{}TLL@{}}
Label 1 & 62 & 79 \\
Label 2 & & \\
Label 3 & & 31 \\
Label 4 & 45 & \\
\end{tabularx}
\end{document}
答案1
我使用listofitems
包来解析\BODY
。tabular
对于每一行,我都会搜索 2-n 列以查找空格以外的数据。如果找到,我将设置为\rowstatus
。T
如果\rowstatus
最终为T
,我将行的标记附加到宏 ( \tabdatatoks
) 中以供以后使用。否则,我会在 [失败] 的空白行的标记中搜索\hline
。如果找到,我还会将其附加到已保存的标记列表中,即使该行原本是空白的。
搜索完成后,我tabular
使用已保存的标记列表进行编写。
已编辑以处理额外的行分隔符,例如\toprule
,除了 之外,\midrule
和。其他内容可以轻松添加到行中,但有一个条件...行分隔符不能接受参数(例如)。\bottomrule
\hline
\setsepchar{\hline||\bottomrule||\toprule}
\cline{1,3}
REEDITED 现已正确处理\cmidrule(x){x-x}
和的实例。任何采用和\cline{x-x}
以外的参数的行分隔符都需要添加额外的代码。\cmidrule
\cline
\documentclass{article}
\usepackage{listofitems,environ,booktabs}
\makeatletter
\NewEnviron{mytab}[2][c]{%
\setsepchar{\\/&}%
\readlist\mytabdata{\BODY}%
\def\tabdatatoks{}%
\foreachitem\tabrow\in\mytabdata[]{%
\gdef\rowstatus{F}%
\foreachitem\tabcol\in\mytabdata[\tabrowcnt]{%
\ifnum\tabcolcnt=1\relax\else%
\setsepchar{ }%
\readlist\mytabcell{\tabcol}%
\foreachitem\cellpart\in\mytabcell[]{%
\expandafter\ifx\expandafter\relax\cellpart\relax\else\gdef\rowstatus{T}\fi%
}%
\fi%
}%
\if T\rowstatus%
% ADD NONEMPTY ROW DATA TO TOKEN LIST
\expandafter\g@addto@macro\expandafter\tabdatatoks\expandafter{\tabrow\\}%
\else%
% FOR EMPTY ROWS, SEARCH FOR AND RETAIN ROW SEPARATOR LINES
\setsepchar{\hline||\cline||\bottomrule||\midrule||\toprule||\cmidrule}%
\expandafter\readlist\expandafter\rowsep\expandafter{\tabrow\ }%
\foreachitem\x\in\rowsep[]{%
\ifnum\xcnt=\listlen\rowsep[]\else%
% ADD ROW SEPARATOR TO TOKEN LIST
\expandafter\expandafter\expandafter\g@addto@macro%
\expandafter\expandafter\expandafter\tabdatatoks%
\expandafter\expandafter\expandafter{\rowsepsep[\xcnt]}%
% SPECIAL PROVISIONS FOR ROW SEPARATORS WITH ARGUMENTS:
\checkforsep{\cmidrule}{\getcmidruleargs}%
\checkforsep{\cline}{\getclineargs}%
\fi%
}%
\fi%
}%
\def\tmp{\begin{tabular}[#1]{#2}}\expandafter\tmp\tabdatatoks\end{tabular}%
}
\newcommand\checkforsep[2]{%
\expandafter\expandafter\expandafter\ifx\rowsepsep[\xcnt]#1%
\expandafter\expandafter\expandafter#2\rowsep[\numexpr\xcnt+1\relax]\relax\fi%
}
\def\getcmidruleargs(#1)#2#3\relax{\g@addto@macro\tabdatatoks{(#1){#2}}}
\def\getclineargs#1#2\relax{\g@addto@macro\tabdatatoks{{#1}}}
\makeatother
\begin{document}
\begin{mytab}{lrr}
\toprule
Label 1 & 62 & 79 \\
\cmidrule(r){1-1}\cmidrule(r){3-3}
Label 2 & & \\
Label 3 & & 31 \\
\cline{1-1}\cline{3-3}
Label 4 & & \\
Label 5 & 45 & \today \\
\bottomrule
\end{mytab}\bigskip
For comparison, normal tabular:\medskip
\begin{tabular}{lrr}
\toprule
Label 1 & 62 & 79 \\
\cmidrule(r){1-1}\cmidrule(r){3-3}
Label 2 & & \\
Label 3 & & 31 \\
\cline{1-1}\cline{3-3}
Label 4 & & \\
Label 5 & 45 & \today \\
\bottomrule
\end{tabular}
\end{document}