为什么当两个组成 \cline 类宏都起作用时,这个 \@ifstar 构造不起作用?

为什么当两个组成 \cline 类宏都起作用时,这个 \@ifstar 构造不起作用?

我有一个宏,可以制作\cline用户指定厚度的。我想创建一个*和未*版本来解释两者之间的差异\cline取决于序列中是否存在多个(例如\cline{1-2}\cline{5-6})。(当\cline规则很粗时,它们可能会破坏下面行的部分/所有内容,除非\vskip最后有一个更正。)

无星号版本\vskip在末尾添加了这个,你可以将它用作\cline序列的最后一个(这包括它是唯一的 的情况\cline)。带星号的版本省略了这个\vskip,你可以将它用作序列中除最后一个之外的所有\cline。在下面的代码中,\ClineTStar是没有更正的带星号的宏\vskip。然后我定义\ClineTNoStar简单地调用并在末尾\ClineTStar添加更正。\vskip

当我使用不同的名称调用这些宏时,它们可以正常工作。请参见下面的输出。\cline以 开头的行后面的带星号的 sA & …会破坏下面的行(该行应以 开头I & J & K…)。但是\cline行后面的 s Q & R…(两个带星号的宏后面跟着一个不带星号的宏)会为下一行的内容留出空间Y & Z…

但我想将这对宏称为和\ClineT*\ClineT当我按照传统\@ifstar方法创建这些风格并调用任一版本时,我收到如下错误消息:

放错位置 \omit。 \@ClineTStar #1-#2#3\@nil ->\omit \@multicnt #1\advance \@multispan \m@ne \i... l.36 \ClineT*{1-2}{10pt} \ClineT*{4-5}{10pt} \ClineT{7-8}{10pt}

我已注释掉该行,\ClineT*{1-2}{10pt} \ClineT*{4-5}{10pt} \ClineT{7-8}{10pt}以便它能够编译。

我做错了什么?(我不想使用 LaTeX3 方法,因为据我所知,它与 Overleaf v1 不兼容。所以我想修复这种\@ifstar方法。)

\documentclass{article}
\makeatletter
\def\ClineTStar#1#2{\@ClineTStar#1#2\@nil}
\def\@ClineTStar#1-#2#3\@nil{%
    \omit
    \@multicnt#1%
    \advance\@multispan\m@ne
    \ifnum\@multicnt=\@ne\@firstofone{&\omit}\fi
    \@multicnt#2%
    \advance\@multicnt-#1%
    \advance\@multispan\@ne
    \leaders\hrule\@height#3\hfill
    \cr
    \noalign{\vskip-#3}%
}
\makeatother
\newcommand{\ClineTNoStar}[2]{%
    \ClineTStar{#1}{#2}%
    \noalign{\vskip#2}%
}

\makeatletter
\newcommand{\ClineT}{\@ifstar{\ClineTStar}{\ClineTNoStar}}
\makeatother

\begin{document}
\begin{tabular}{| c | c | c | c | c | c | c | c |}
\hline
A & B & C & D & E & F & G & H \\
\ClineTStar{1-2}{10pt} \ClineTStar{4-5}{10pt} \ClineTStar{7-8}{10pt}
I & J & K & L & M & N & O & P \\
Q & R & S & T & U & V & W & X \\
\ClineTStar{1-2}{10pt} \ClineTStar{4-5}{10pt} \ClineTNoStar{7-8}{10pt}
Y & Z & A & B & C & D & E & F \\
%\ClineT*{1-2}{10pt} \ClineT*{4-5}{10pt} \ClineT{7-8}{10pt}
E & F & G & H & I & J & K & L \\
\hline
\end{tabular}
\end{document}

enter image description here

答案1

这里的问题是,\omit必须是表格单元格中在 之后出现的第一个命令\\。如果您在那里使用宏,它们必须是完全可扩展的,并且\omit必须是该扩展的第一个标记。由于在\@ifstar决定下一个标记是否为 之前使用了多个赋值*,因此它会在这里失败。所以我们必须\ClineT用一个完全可扩展的宏来替换:

\documentclass{article}
\makeatletter
\def\ClineTStar#1#2{\@ClineTStar#1#2\@nil}
\def\@ClineTStar#1-#2#3\@nil{%
    \omit
    \@multicnt#1%
    \advance\@multispan\m@ne
    \ifnum\@multicnt=\@ne\@firstofone{&\omit}\fi
    \@multicnt#2%
    \advance\@multicnt-#1%
    \advance\@multispan\@ne
    \leaders\hrule\@height#3\hfill
    \cr
    \noalign{\vskip-#3}%
}
\makeatother
\newcommand{\ClineTNoStar}[2]{%
    \ClineTStar{#1}{#2}%
    \noalign{\vskip#2}%
}

\makeatletter
\def\ClineT#1{%
    \expandafter\ifx\@firstofmany#1\relax\@end*%
        \expandafter\ClineTStar
    \else
        \ClineT@#1%
    \fi
}
\def\ClineT@#1\fi{\fi\ClineTNoStar{#1}}
\def\@firstofmany#1#2\@end{#1}
\makeatother

\begin{document}
\begin{tabular}{| c | c | c | c | c | c | c | c |}
\hline
A & B & C & D & E & F & G & H \\
\ClineTStar{1-2}{10pt} \ClineTStar{4-5}{10pt} \ClineTStar{7-8}{10pt}
I & J & K & L & M & N & O & P \\
Q & R & S & T & U & V & W & X \\
\ClineTStar{1-2}{10pt} \ClineTStar{4-5}{10pt} \ClineTNoStar{7-8}{10pt}
Y & Z & A & B & C & D & E & F \\
\ClineT*{1-2}{10pt} \ClineT*{4-5}{10pt} \ClineT{7-8}{10pt}
E & F & G & H & I & J & K & L \\
\hline
\end{tabular}
\end{document}

enter image description here

\ClineT接受一个参数,该参数要么是 ,*要么是 之类的组{1-2}。我们使用辅助宏找到该参数的第一个标记,\*firstofmany并将其与 进行比较*。如果它们相同,\ClineTStar则接下来要调用的是 。

另一个分支有点棘手,因为我们需要重新应用已经读取的参数\ClineTNoStar。根本\else\ClineTNoStar{#1}\fi行不通——现在\fi将成为的第二个参数\ClineTNoStar。解决方案是使用辅助宏,该宏使用\fi分隔参数,立即将其放回标记流并调用实际宏作为扩展的最后一部分。

相关内容