当我尝试使用\cmidrule
s 来维护大型表格时,我发现它们使用起来很乏味,所以我想定义自己的快捷方式。\cmidrule{1-3} \cmidrule{4-5}
我不会直接写,而是直接写\cmidrulez{3,2}
(因为第一条规则是 3 列宽,第二条规则是 2 列宽)。
为了支持任意数量的逗号分隔的参数,我尝试调整这个答案:
\newcounter{mainargs}
\pgfkeys{mainargs/.is family, mainargs,
step counter/.code=\stepcounter{mainargs},
add argument/.style={step counter, arg\themainargs/.initial={#1}},
}
\newcounter{optargs}
\newif\ifoptargs
\pgfkeys{optargs/.is family, optargs,
opt args present/.is if=optargs,
step counter/.code=\stepcounter{optargs},
add argument/.style={opt args present=true, step counter, arg\theoptargs/.initial={#1}},
}
\newcommand{\cmidrulez}[2][]{%
\setcounter{mainargs}{0}%
\pgfkeys{mainargs, add argument/.list={#2}}%
\setcounter{optargs}{0}%
\pgfkeys{optargs, add argument/.list={#1}}%
%
\newcounter{cmrstart}%
\newcounter{cmrend}%
\setcounter{cmrstart}{1}%
\ifoptargs%
\foreach \n in {1,...,\theoptargs}{%
\setcounter{cmrstart}{\pgfkeysvalueof{/optargs/arg\n}}%
}%
\fi%
\foreach \n in {1,...,\themainargs}{%
\setcounter{cmrend}{\value{cmrstart}}%
\addtocounter{cmrend}{\pgfkeysvalueof{/mainargs/arg\n}}%
\addtocounter{cmrend}{-1}%
\cmidrule{\arabic{cmrstart}-\arabic{cmrend}}%
\setcounter{cmrstart}{\value{cmrend}}%
\stepcounter{cmrstart}%
}%
%
}
本质上,我所做的是使用两个计数器来计算我需要提供给命令的相应数字。当我使用 和而不是\cmidrule
调用 打印数字时,会出现正确的值,所以这部分是有效的。\arabic{cmrstart}
\arabic{cmrend}
\cmidrule
但是,当我尝试在表格中使用它(可以\cmidrule
工作)时,它会抱怨“放错位置的 \noalign”:
\cmidrule ->\noalign
{\ifnum 0=`}\fi \@ifnextchar [{\@cmidrule }{\@cmidrule ...
l.66 \cmidrulez{2,1}
\\
I expect to see \noalign only after the \cr of
an alignment. Proceed, and I'll ignore this case.
! Missing } inserted.
<inserted text>
}
l.66 \cmidrulez{2,1}
\\
我首先想到这可能与我传递值的方式有关,所以我尝试了\value{cmrstart}
和thecmrstart
,这是我所知道的另外两种从计数器获取值的方法,但没有奏效。事实上,如果我只是\cmidrule
用硬编码整数替换的参数(在我的命令定义中),问题仍然存在,所以不可能(仅仅)是那样。
当我定义一个更简单的命令时,它只执行类似的操作,\cmidrule{1-3}
没有任何问题,但只要有参数它就会失败:
% this works:
\newcommand{\cmidrules}{%
\cmidrule{1-3}%
}
% this doesn't:
\newcommand{\cmidrules}[1][]{%
\cmidrule{1-3}%
}
我究竟做错了什么?
答案1
您不能在发布之前进行分配\cmidrule
,除非它们在内部\noalign
。
这是我的版本,我还添加了*
以留空一列。我还添加了(lr)
,\cmidrule
否则\cmidrule{1-3}\cmidrule{4-5}
将与 完全相同\cmidrule{1-5}
。
\documentclass{article}
\usepackage{booktabs}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\cmidrulez}{m}
{
\noalign { \__leviathan_cmidrulez:n { #1 } }
\tl_use:N \g__leviathan_cmidrulez_tl
}
\tl_new:N \g__leviathan_cmidrulez_tl
\int_new:N \l__leviathan_cmidrulez_int
\cs_new_protected:Nn \__leviathan_cmidrulez:n
{
\tl_gclear:N \g__leviathan_cmidrulez_tl
\int_zero:N \l__leviathan_cmidrulez_int
\clist_map_inline:nn { #1 }
{
\str_if_eq:nnTF { ##1 } { * }
{% no rule here
\int_incr:N \l__leviathan_cmidrulez_int
}
{
\tl_gput_right:Nx \g__leviathan_cmidrulez_tl
{
\exp_not:N \cmidrule(lr)
{% start
\int_eval:n { \l__leviathan_cmidrulez_int + 1 }
-
\int_eval:n { \l__leviathan_cmidrulez_int + ##1 }
}
}
\int_add:Nn \l__leviathan_cmidrulez_int { ##1 }
}
}
}
\ExplSyntaxOff
\begin{document}
\begin{tabular}{*{9}{c}}
\toprule
1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
\cmidrulez{3,2}
1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
\cmidrulez{*,3,*,2}
1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
\bottomrule
\end{tabular}
\end{document}
扫描逗号分隔的列表,如果项目是,则*
内部计数器将步进。否则,使用计数器的当前值(加 1)和所需的步数准备适当的参数。然后更新计数器。命令附加到结束\cmidrule
后发出的令牌列表变量中。\noalign
但我不确定这有多大用处。\cmidrule
你的文档中有多少个命令?
答案2
该位置的宏需要可扩展以避免启动下一个表格单元格。
在这种情况下,直接查看扩展的工作原理可能比使用包代码更容易。
\documentclass{article}
\usepackage{array,booktabs}
\def\cmidrulez#1{\cmz{}1#1,{-1},}
\def\gobblethree#1#2#3{}
\def\cmz#1#2#3,{%
\ifnum#3=-1
#1\expandafter\gobblethree\fi
\cmz{#1\cmidrule(lr){#2-\the\numexpr#2+#3-1\relax}}{\the\numexpr#2+#3\relax}}
\begin{document}
\begin{tabular}{ccccc}
1&2&3&4&5\\
\cmidrulez{3,2}
1&2&3&4&5\\
1&2&3&4&5\\
\end{tabular}
\end{document}
答案3
具有“可扩展”编程的解决方案。
\documentclass{article}
\usepackage{array}
\usepackage{booktabs}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand { \clinez } { m } { \__leviathan:nn { 1 } { #1 , } }
\cs_new:Nn \__leviathan:nn
{ \tl_if_empty:nF { #2 } { \__leviathan:nnn #2 \q_stop { #1 } } }
\cs_new:Npn \__leviathan:nnn #1 , #2 \q_stop #3
{
\str_if_eq:nnTF { #1 } { * }
{ \__leviathan:nn { \int_eval:n { #3 + 1 } } { #2 } }
{
\__leviathan:nn { \int_eval:n { #1 + #3 } } { #2 }
\cmidrule (lr) { #3 - \int_eval:n { #3 + #1 - 1 } }
}
}
\ExplSyntaxOff
\begin{document}
\begin{tabular}{*{10}{c}}
a & b & c & d & e & f & g & h & i & j \\
\clinez{3,2,2}
a & b & c & d & e & f & g & h & i & j \\
\clinez{3,*,2,2}
a & b & c & d & e & f & g & h & i & j \\
\end{tabular}
\end{document}