将 \cmidrule 包装在宏中

将 \cmidrule 包装在宏中

在我之前的解决方案中使用 LaTeX 进行多元多项式长除法我已经将其包装\cmidrule在一个宏中,因为其允许缩短端点的语法不是标准的:

\newcommand*{\CMidRule}[3]{\cmidrule[\cmidrulewidth](l{#1}r{#2}){#3}}%

我想用xparse允许两个 shift 参数可选,但随后遇到了问题。

  1. 仅使用这个一次每行都可以正常工作,如上面链接的问题所示。但是,尝试将其用于两个单独的操作\cmidrule是有问题的,因为在后续使用之间会产生垂直移位(如下面第三个表格所示)。

    在此处输入图片描述

  2. \NewDocumentCommand此外我尝试使用包裹xparse允许两个可选参数甚至无法编译(因此注释掉了第四个表中的行)。错误消息是:

    Misplaced \noalign.
    \cmidrule ->\noalign 
                        {\ifnum 0=`}\fi \@ifnextchar [{\@cmidrule }{\@cmidrule ...
     l.40 \CMidRuleX{0.0ex}
                           {0.0ex}{1-1}\CMidRuleX{0.0ex}{0.0ex}{2-2}
    

参考:

问题:

  • 我该如何正确定义\NewDocumentCommand{\CMidRuleX}{O{0.0ex} O{0.0ex} m}{}

代码:

\documentclass{article}
\usepackage{booktabs}
\usepackage{xparse}

\newcommand*{\CMidRule}[3]{\cmidrule[\cmidrulewidth](l{#1}r{#2}){#3}}%

\NewDocumentCommand{\CMidRuleX}{%
    O{0.0ex}% #1 = left adjust
    O{0.0ex}% #1 = right adjust
    m%   #3 = columns to span
    }{%
    \cmidrule[\cmidrulewidth](l{#1}r{#2}){#3}%
}%


\begin{document}
\section*{Direct use of cmidrule works just fine}
\begin{tabular}{rc}
  Left & Right \\
  \cmidrule{1-1}\cmidrule{2-2}
    2  &   3   \\
\end{tabular}
\hspace{1.0cm}
\begin{tabular}{rc}
  Left & Right \\
  \cmidrule[\cmidrulewidth](l{0.0ex}r{0.5ex}){1-1}\cmidrule[\cmidrulewidth](l{0.5ex}r{0.0ex}){2-2}
    2  &   3   \\
\end{tabular}
%
\bigskip
\section*{Wrapping cdmidrule in a macro does not work}
\begin{tabular}{rc}
  Left & Right \\
  \CMidRule{0.0ex}{0.5ex}{1-1}\CMidRule{0.5ex}{0.0ex}{2-2}
    2  &   3   \\
\end{tabular}
\hspace{1.0cm}
\begin{tabular}{rc}
  Left & Right \\
  %\CMidRuleX[0.0ex][0.0ex]{1-1}\CMidRuleX[0.0ex][0.0ex]{2-2}
    2  &   3   \\
\end{tabular}
\end{document}

答案1

在表格中,插入行之间的材料(例如规则)是使用 TeX 基元添加的\noalign。也就是说, 的简单定义\hline可以是:“独立于当前对齐方式\noalign{\hrule}插入水平线( )。这应该出现在 内使用的基元之后,用于结束一行。\hrule\noalign\cr\\

正如我在最近的回答中解释的那样TeX 如何以及为何寻找\noalign\noalign之后,TeX 会逐个搜索 ,\cr并递归扩展 后面的第一个标记\cr。它会在任何不可扩展的标记或任何受保护的宏处停止。

问题在于,在您的情况下,TeX 不够努力,无法找到\noalign中的隐藏项\CMidRuleX。事实上,稳健地寻找可选参数是不可扩展的,它需要分配,并且诸如\hrule或 之类的宏\cmidrule必须在 TeX 上耍花招才能成功获取可选参数。

您的第一个选择是:使用\DeclareExpandableDocumentCommand来创建可扩展的命令。搜索可选参数不再十分可靠,但由于宏以强制参数结尾,因此应该没问题。

\DeclareExpandableDocumentCommand{\CMidRuleX}{%
    O{0.0ex}% #1 = left adjust
    O{0.0ex}% #1 = right adjust
    m%   #3 = columns to span
}{%
    \cmidrule[\cmidrulewidth](l{#1}r{#2}){#3}%
}%

第二种选择:在 TeX 上玩些小把戏。首先使用\noalign\bgroup进入无对齐世界,然后查找可选参数。找到可选参数后,\noalign使用 结束您的组\egroup,然后插入\cmidrule业务。

\newcommand{\CMidRuleY}{\noalign\bgroup\CMidRuleYaux}
\NewDocumentCommand{\CMidRuleYaux}{%
    O{0.0ex}% #1 = left adjust
    O{0.0ex}% #1 = right adjust
    m%   #3 = columns to span
}{%
    \egroup
    \cmidrule[\cmidrulewidth](l{#1}r{#2}){#3}%
}%

\cmidrule这两种解决方案都无法解决连续两个无法对齐的问题。对齐的唯一方法是第一个\cmidrule必须知道它后面跟着另一个\cmidrule。由于我们隐藏\cmidrule在宏中,我们必须自己进一步检查\cmidrule

\documentclass{article}
\usepackage{xparse, booktabs}
\newcommand{\CMidRuleZ}{\noalign\bgroup\CMidRuleZaux{}}
\ExplSyntaxOn
\makeatletter
\NewDocumentCommand{\CMidRuleZaux}{
    m % Material to reinsert before cmidrule.
    O{0.0ex} % #1 = left adjust
    O{0.0ex} % #1 = right adjust
    m  %   #3 = columns to span
}{
    \peek_meaning_remove_ignore_spaces:NTF \CMidRuleZ
      { \CMidRuleZaux { #1 \cmidrule[\cmidrulewidth](l{#2}r{#3}){#4} } }
      { \egroup #1 \cmidrule[\cmidrulewidth](l{#2}r{#3}){#4} }
}
\makeatother
\ExplSyntaxOff
\begin{document}
\begin{tabular}{ccccccccc}
  a & b & c & d & e & f & g & h \\
  \CMidRuleZ{1-2}
  \CMidRuleZ{4-5}
  \CMidRuleZ{7-8}
\end{tabular}
\end{document}

编辑:改变方法,\CMidRuleZ先收集所有内容,然后连续调用\cmidrule

相关内容