防止 clist_map_inline 之后换行

防止 clist_map_inline 之后换行

我正在尝试自动创建某些表单,其中一部分工作是自动在类似表格的表单中创建正确数量的空白行。这导致我出现了以下奇怪的行为:

\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new_eq:NN \clistMap \clist_map_inline:nn
\ExplSyntaxOff

\begin{document}
\begin{tabular}{|ll|}
\clistMap{one, two, three}{#1 &\\\hline}
\end{tabular}

\begin{tabular}{|ll|}
one &\\\hline
two &\\\hline
three &\\\hline
\end{tabular}
\end{document}

这两个表格的排版方式不同。我不明白为什么。第一个表格的三行后面有一个尾行。我说尾行,是因为下面的这个表格的排版方式与第一个表格相同。

\begin{tabular}{|ll|}
    one &\\\hline
    two &\\\hline
    three &\\\hline
    \\
\end{tabular}

作为最后一对尽可能简单的例子,请注意以下两个表的相同外观:

\begin{tabular}{|ll|}
    \clistMap{}{#1 &\\\hline}
\end{tabular}

\medskip % So you can see where one table ends and the other begins.

\begin{tabular}{|ll|}
    \\
\end{tabular}

我该如何去掉这个尾随的换行符?为了加分 --- 如果您愿意的话,我未来的回答者 --- 如何检测是否存在其他意外的控制序列?我尝试使用 fancyvrb 命令来执行此操作,但始终无法完全得到我想要的结果;我无法检测到控制序列\\,其他字符也会 &导致问题。我还尝试使用 trace 包,类似于\clistMap扩展为大约 1000 行的扩展宏。

答案1

您需要使用\clist_map_function:nN,定义一个临时函数:

\documentclass{article}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\clistMap}{mm}
 {
  \cs_gset:Nn \__beelzebielsk_map:n { #2 }
  \clist_map_function:nN { #1 } \__beelzebielsk_map:n
 }
\ExplSyntaxOff

\begin{document}

\begin{tabular}{|l|l|}
\hline
\clistMap{one, two, three}{#1 &\\\hline}
\end{tabular}
\qquad
\begin{tabular}{|l|l|}
\hline
one &\\\hline
two &\\\hline
three &\\\hline
\end{tabular}

\end{document}

问题在于,\clist_map_inline:nn当 TeX 意识到循环已结束时,它会让 TeX 处于新单元已启动的状态。

在此处输入图片描述

这实际上是这样\clist_map_inline:nn做的:它定义了一个新的“未命名”函数并使用\clist_map_function:nN它。但是,它还必须掩盖其踪迹,特别是为了便于嵌套使用,为此它使用了一个必须在最后逐步降低的计数器:这是创建不需要的额外行的操作。

更明确地说:\clist_map_inline:nn { <clist> } { <code> }大致如此

\int_incr:Nn \<reserved>_int
\cs_gset:cn { <reserved> \int_eval:n \<reserved>_int :n } { <code> }
\clist_map_function:nc { <clist> } { <reserved> \int_eval:n \<reserved>_int :n }
\int_decr:Nn \<reserved>_int

传递给 so 的函数\clist_map_function:nc取决于嵌套级别,因为保留计数器与 clist 映射相关联。这允许\clist_map_inline:nn在其第二个参数中包含一个 inner \clist_map_inline:nn,它将\clist_map_function:nc使用不同的功能。

但是,\int_decr:Nn \<reserved>_int对于你的情况,该操作将触发 TeX 开始一个新单元。TeX 表总是很叛逆;-)。。

根据所提出的定义,计数器上的操作被跳过;当然你不能\clistMap嵌套\clistMap

答案2

我相信每个人都会原谅我的有些离题的回答,这只是提供一个说明@egreg 解释的例子:

\documentclass{article}
\usepackage{xinttools}
\begin{document}
\begin{tabular}{|ll|}
\hline
\xintFor #1 in {one, two, three}:
{#1 &\\\hline}
\end{tabular}
\begin{tabular}{|ll|}
\hline
one &\\\hline
two &\\\hline
three &\\\hline
\end{tabular}
\end{document}

在此处输入图片描述

虽然\xintFor行为不可扩展,但要小心不要做任何“纯扩展不消失”的事情在其末端。这样它就不会意外触发新行。但是,此约束对功能有一些限制作用\xintFor(请参阅 xint.pdf 中方框内的“15.17 \xintifForFirst、\xintifForLast”注释)。

请注意,嵌套\xintFor很好。

这里的补充说明是关于(放大时)在两个(相同)表格中的水平线和垂直线连接处看到的奇怪的“间隙”:添加\usepackage{array} 以修复该问题。

答案3

您可以使用以下方法使原始函数在此位置安全\noalign

\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new_eq:NN \clistMap \clist_map_inline:nn
\ExplSyntaxOff

\begin{document}
\begin{tabular}{|ll|}
\noalign\bgroup\clistMap{one, two, three}{\egroup#1 &\\\hline\noalign\bgroup}\egroup
\end{tabular}

\begin{tabular}{|ll|}
one &\\\hline
two &\\\hline
three &\\\hline
\end{tabular}
\end{document}

相关内容