我想创建一个可以生成如下表格的宏:
\documentclass{minimal}
\begin{document}
\begin{tabular}{c|c|c}
A & 1 & 2 & 3 \\
B & 0 & 1 & 1 \\
C & 0 & 0 & 1
\end{tabular}
\end{document}
我希望能够定义一个\columns{1,2,3}
包含每列标题的列表,以及一个\rows{A,B,C}
包含每行第一个元素的列表。
对于其余的条目,也许是类似的\entries{011,001}
,我不确定最好的方法是什么。
最终,我想要一个具有类似语法的宏
\mymacro{\columns}{\rows}{\entries}
我最近才开始编写自己的宏,但我还没有找到任何能满足我要求的东西,也不知道该如何进行。
谢谢!
答案1
有趣的问题,但是真的有好处吗?
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% user interface
\NewDocumentCommand{\mymacro}{mmm}
{% #1 = column headers, #2 = row headers, #3 = entries
\gabriel_mymacro:nnn { #1 } { #2 } { #3 }
}
% variables
\tl_new:N \l__gabriel_mymacro_body_tl
\tl_new:N \l__gabriel_mymacro_row_tl
\seq_new:N \l__gabriel_mymacro_entries_seq
% functions
\cs_new_protected:Nn \gabriel_mymacro:nnn
{
% clear the tl containing the body and collect the entries
\tl_clear:N \l__gabriel_mymacro_body_tl
\seq_set_split:Nnn \l__gabriel_mymacro_entries_seq { , } { #3 }
% make the first row
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #2 } { 1 }
}
\clist_map_function:nN { #1 } \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ \hline }
% build the following rows
\int_step_inline:nn { \clist_count:n { #2 } - 1 }
{
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #2 } { ##1 + 1 }
}
\seq_pop_left:NN \l__gabriel_mymacro_entries_seq \l__gabriel_mymacro_row_tl
\tl_map_function:NN \l__gabriel_mymacro_row_tl \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ }
}
% typeset the table
\begin{tabular}{c *{ \clist_count:n { #1 } } { |c } }
\tl_use:N \l__gabriel_mymacro_body_tl
\end{tabular}
}
\cs_new_protected:Nn \__gabriel_mymacro_add_entry:n
{
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { & #1 }
}
\ExplSyntaxOff
\begin{document}
\mymacro{1,2,3}{A,B,C}{011,001}
\bigskip
\mymacro{Apple,Banana,Cherry,Date}{X,Apple,Banana,Cherry,Date}{
0000,0101,1111,1010
}
\end{document}
带有可选参数的变体,用于指定列对齐。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% user interface
\NewDocumentCommand{\mymacro}{ommm}
{% #2 = column headers, #3 = row headers, #4 = entries
\IfNoValueTF { #1 }
{
\gabriel_mymacro:nnnn { c *{ \clist_count:n { #2 } } { |c } } { #2 } { #3 } { #4 }
}
{
\gabriel_mymacro:nnnn { #1 } { #2 } { #3 } { #4 }
}
}
% variables
\tl_new:N \l__gabriel_mymacro_body_tl
\tl_new:N \l__gabriel_mymacro_row_tl
\seq_new:N \l__gabriel_mymacro_entries_seq
% functions
\cs_new_protected:Nn \gabriel_mymacro:nnnn
{
% clear the tl containing the body and collect the entries
\tl_clear:N \l__gabriel_mymacro_body_tl
\seq_set_split:Nnn \l__gabriel_mymacro_entries_seq { , } { #4 }
% make the first row
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #3 } { 1 }
}
\clist_map_function:nN { #2 } \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ \hline }
% build the following rows
\int_step_inline:nn { \clist_count:n { #3 } - 1 }
{
\tl_put_right:Nx \l__gabriel_mymacro_body_tl
{
\clist_item:nn { #3 } { ##1 + 1 }
}
\seq_pop_left:NN \l__gabriel_mymacro_entries_seq \l__gabriel_mymacro_row_tl
\tl_map_function:NN \l__gabriel_mymacro_row_tl \__gabriel_mymacro_add_entry:n
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { \\ }
}
% typeset the table
\begin{tabular}{#1}
\tl_use:N \l__gabriel_mymacro_body_tl
\end{tabular}
}
\cs_new_protected:Nn \__gabriel_mymacro_add_entry:n
{
\tl_put_right:Nn \l__gabriel_mymacro_body_tl { & #1 }
}
\ExplSyntaxOff
\begin{document}
\mymacro{1,2,3}{A,B,C}{011,001}
\bigskip
\mymacro{Apple,Banana,Cherry,Date}{X,Apple,Banana,Cherry,Date}{
0000,0101,1111,1010
}
\bigskip
\mymacro[l|cccc]{Apple,Banana,Cherry,Date}{X,Apple,Banana,Cherry,Date}{
0000,0101,1111,1010
}
\end{document}