我想用宏创建一个表。不幸的是,我得到了一个错误。下面是一个简单的例子:
\documentclass[a4paper,12pt]{article}
\begin{document}
\ExplSyntaxOn
%%% Create a new table nxn
%%% First parameter: number of lines and columns
%%% Second parameter: entries of the table
\NewDocumentCommand{\TableCreate}{mm}{
\int_set:Nn \l_tmpa_int {1}
\begin{tabular}{|c|c|c|c|}
\hline
\int_do_until:nNnn {\l_tmpa_int} > {#1}
{
%%% Test if this the last column of the line
\int_compare:nNnTF {\l_tmpa_int} = {#1}
{
%%% This is the last colum
\clist_item:nn {#2} {\l_tmpa_int} & \\ \hline
}
{
%%% This is not the last column
\clist_item:nn {#2} {\l_tmpa_int} &
}
}
\hline
\end{tabular}
}
\ExplSyntaxOff
\TableCreate{4}{1,2,3,4}
\end{document}
这里我有一个宏TableCreate{4}{1,2,3,4}
。我想创建一个一行四列的表格。当我想在单元格中写入内容时,我必须测试它是否是最后一列。这就是我使用的原因
\int_do_until:nNnn {\l_tmpa_int} > {#1}
我使用变量\l_tmpa_int
来迭代列。我使用宏的第一个参数来了解我有多少列。稍后我想创建列数与行数不相同的表。当我编译此代码时,我得到:
! Extra alignment tab has been changed to \cr.
<recently read> \endtemplate
l.33 \TableCreate{4}{1,2,3,4}
我不明白为什么会出现这个错误。
感谢您的帮助。
答案1
正如 David 所说,您在处理组时遇到了问题(而且您缺少\int_incr:N
实际逐步执行的clist
)。代码中的最小更改变体是简单地使用全局变量而不是本地 int 变量。请注意,我将调用放在\int_gincr:N
每个单元格前面,并使用来-1
补偿这一点。这是必要的,因为如果您将它放在后面,\\ \hline
您最终会在第二行的第一个单元格中得到不可扩展的材料,并在输出中获得第二行。
此外,以下代码不使用硬编码的 4 列数,而是*{#1}{c|}
使用所需的精确列数。
\documentclass[a4paper,12pt]{article}
\ExplSyntaxOn
\int_new:N \g_LucArmand_tmp_int
%%% Create a new table nxn
%%% First parameter: number of lines and columns
%%% Second parameter: entries of the table
\NewDocumentCommand \TableCreate { m m }
{
\int_gset_eq:NN \g_LucArmand_tmp_int \c_one_int
\begin{tabular}{|*{#1}{c|}}
\hline
\int_do_until:nNnn {\g_LucArmand_tmp_int} > {#1}
{
\int_gincr:N \g_LucArmand_tmp_int
\clist_item:nn {#2} { \g_LucArmand_tmp_int - 1 }
%%% Test if this the last column of the line
\int_compare:nNnTF { \g_LucArmand_tmp_int - 1 } = {#1}
{ %%% This is the last column
\\ \hline
}
{ %%% This is not the last column
&
}
}
\end{tabular}
}
\ExplSyntaxOff
\begin{document}
\TableCreate{4}{1,2,3,4}
\end{document}
但我们可以进一步改进这一点。为什么需要指定元素的数量,我们可以让 TeX 为我们进行计数(这使用一个可选参数默认为 的数量clist
):
\documentclass[a4paper,12pt]{article}
\ExplSyntaxOn
\int_new:N \g_LucArmand_tmp_int
%%% Create a new table nxn
%%% First parameter: number of lines and columns
%%% Second parameter: entries of the table
\NewDocumentCommand \TableCreate { O{\clist_count:n{#2}} m }
{
\int_gset_eq:NN \g_LucArmand_tmp_int \c_one_int
\begin{tabular}{|*{#1}{c|}}
\hline
\int_do_until:nNnn {\g_LucArmand_tmp_int} > {#1}
{
\int_gincr:N \g_LucArmand_tmp_int
\clist_item:nn {#2} { \g_LucArmand_tmp_int - 1 }
%%% Test if this the last column of the line
\int_compare:nNnTF { \g_LucArmand_tmp_int - 1 } = {#1}
{ %%% This is the last column
\\ \hline
}
{ %%% This is not the last column
&
}
}
\end{tabular}
}
\ExplSyntaxOff
\begin{document}
\TableCreate[3]{1,2,3,4}
\end{document}
但是第一段和第二段代码都没有实现你在文档注释中指定的行为(行数和列),为此,最简单的解决方案是添加一个\int_mod:nn
调用:
\documentclass[a4paper,12pt]{article}
\ExplSyntaxOn
\int_new:N \g_LucArmand_tmp_int
%%% Create a new table nxn
%%% First parameter: number of lines and columns
%%% Second parameter: entries of the table
\NewDocumentCommand \TableCreate { O{\clist_count:n{#2}} m }
{
\int_gset_eq:NN \g_LucArmand_tmp_int \c_one_int
\begin{tabular}{|*{#1}{c|}}
\hline
\int_do_until:nNnn {\g_LucArmand_tmp_int} > { \clist_count:n {#2} }
{
\int_gincr:N \g_LucArmand_tmp_int
\clist_item:nn {#2} { \g_LucArmand_tmp_int - 1 }
%%% Test if this the last column of the line
\int_compare:nNnTF
{ \int_mod:nn { \g_LucArmand_tmp_int - 1 } {#1} } = \c_zero_int
{ %%% This is the last column
\\ \hline
}
{ %%% This is not the last column
&
}
}
\end{tabular}
}
\ExplSyntaxOff
\begin{document}
\TableCreate[2]{1,2,3,4}
\end{document}
答案2
另一个答案为这项工作提供了充分的理由和好的代码,但还有一种更巧妙的方法。
\documentclass[a4paper,12pt]{article}
\ExplSyntaxOn
\int_new:N \l__lucarmand_tablecreate_cols_int
\seq_new:N \l__lucarmand_tablecreate_body_seq
%%% First parameter: number of lines and columns
%%% Second parameter: entries of the table
\NewDocumentCommand \TableCreate { O{\clist_count:n{#2}} m }
{
\int_set:Nn \l__lucarmand_tablecreate_cols_int { #1 }
\seq_set_from_clist:Nn \l__lucarmand_tablecreate_body_seq { #2 }
\begin{tabular}{|*{#1}{c|}}
\hline
\seq_map_indexed_function:NN \l__lucarmand_tablecreate_body_seq \__lucarmand_tablecreate:nn
\end{tabular}
}
\cs_new_protected:Nn \__lucarmand_tablecreate:nn
{
#2 % the entry
\int_compare:nTF { \int_mod:nn { #1 } { \l__lucarmand_tablecreate_cols_int } == 0 }
{% end of row
\\ \hline
}
{% still columns to go
&
}
}
\ExplSyntaxOff
\begin{document}
\TableCreate[2]{1,2,3,4}
\TableCreate[4]{a,b,c,d,e,f,g,h,i,j,k,l}
\end{document}
表体一次性创建,\\\hline
当索引是列数的倍数时插入,否则&
追加。
我们还可以添加检查,确保项目数是列数的倍数;这里的补救措施是添加?
项目。
\documentclass[a4paper,12pt]{article}
\ExplSyntaxOn
\int_new:N \l__lucarmand_tablecreate_cols_int
\seq_new:N \l__lucarmand_tablecreate_body_seq
%%% First parameter: number of lines and columns
%%% Second parameter: entries of the table
\NewDocumentCommand \TableCreate { O{\clist_count:n{#2}} m }
{
\int_set:Nn \l__lucarmand_tablecreate_cols_int { #1 }
\seq_set_from_clist:Nn \l__lucarmand_tablecreate_body_seq { #2 }
\int_compare:nF
{% is the number of items a multiple of #1?
\int_mod:nn { \seq_count:N \l__lucarmand_tablecreate_body_seq } { #1 } == 0
}
{% no! Add entries
\prg_replicate:nn
{% add the necessary
#1 - \int_mod:nn { \seq_count:N \l__lucarmand_tablecreate_body_seq } { #1 }
}
{% blank entries
\seq_put_right:Nn \l__lucarmand_tablecreate_body_seq { ? }
}
}
\begin{tabular}{|*{#1}{c|}}
\hline
\seq_map_indexed_function:NN \l__lucarmand_tablecreate_body_seq \__lucarmand_tablecreate:nn
\end{tabular}
}
\cs_new_protected:Nn \__lucarmand_tablecreate:nn
{
#2 % the entry
\int_compare:nTF { \int_mod:nn { #1 } { \l__lucarmand_tablecreate_cols_int } == 0 }
{% end of row
\\ \hline
}
{% still columns to go
&
}
}
\ExplSyntaxOff
\begin{document}
\TableCreate[2]{1,2,3,4}
\TableCreate[4]{a,b,c,d,e,f,g,h,i,j,k,l}
\bigskip
\TableCreate[4]{a,b,c,d,e,f,g,h,i,j,k,l,m}
\end{document}