尝试为 cmidrules 定义命令时放错了 \noalign

尝试为 cmidrules 定义命令时放错了 \noalign

当我尝试使用\cmidrules 来维护大型表格时,我发现它们使用起来很乏味,所以我想定义自己的快捷方式。\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}

上述代码的输出

相关内容