在我之前的解决方案中使用 LaTeX 进行多元多项式长除法我已经将其包装\cmidrule
在一个宏中,因为其允许缩短端点的语法不是标准的:
\newcommand*{\CMidRule}[3]{\cmidrule[\cmidrulewidth](l{#1}r{#2}){#3}}%
我想用xparse
允许两个 shift 参数可选,但随后遇到了问题。
仅使用这个一次每行都可以正常工作,如上面链接的问题所示。但是,尝试将其用于两个单独的操作
\cmidrule
是有问题的,因为在后续使用之间会产生垂直移位(如下面第三个表格所示)。\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
。