在我的文档中,我有很多关于格式的表格
\begin{tabular}{l|l||l}
a & b & W\\ \hline
c & d & g\\
e & f & g\\
\end{tabular}
列数可能会有所不同,行数也可能有所不同,但我总是希望有一条双线将最右边的列与其他列分开,并有一条线将第一行和第二行分开。
有什么方法可以让我编写一个自定义命令,允许我编写类似这样的内容
\begin{tabular2}{3}
a & b & W\\
c & d & g\\
e & f & g\\
\end{tabular2}
为了得到相同的结果?
这样我就可以确保我没有在我的许多表格中做出任何微小的格式错误更改
答案1
使用xparse
(参见 2019-03-05 之前版本的编辑历史):
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{bomaztab}{ O{c} m +b }
{
\bomaz_maketable:nnn { #1 } { #2 } { #3 }
}
{}
\tl_new:N \l_bomaz_preamble_tl
\tl_new:N \l_bomaz_firstrow_tl
\seq_new:N \l_bomaz_body_seq
\cs_new_protected:Nn \bomaz_maketable:nnn
{
% #1 = alignment argument, #2 = number of cols, #3 = body
% add #2-1 'l|' cols
\tl_set:Nx \l_bomaz_preamble_tl { \prg_replicate:nn { #2 - 1 }{ l| } }
% add a trailing '|l'
\tl_put_right:Nn \l_bomaz_preamble_tl { |l }
% split the body at \\
\seq_set_split:Nnn \l_bomaz_body_seq { \\ } { #3 }
% detach the first row
\seq_pop_left:NN \l_bomaz_body_seq \l_bomaz_firstrow_tl
% start the tabular
\bomaz_tabular:nV { #1 } \l_bomaz_preamble_tl
% first row is followed by \hline
\l_bomaz_firstrow_tl \\ \hline
% deliver the other rows
\seq_use:Nn \l_bomaz_body_seq { \\ }
% end the tabular
\endtabular
}
% helper function to be varied (start of tabular)
\cs_new_protected:Nn \bomaz_tabular:nn { \tabular[#1]{#2} }
\cs_generate_variant:Nn \bomaz_tabular:nn { nV }
\ExplSyntaxOff
\begin{document}
\begin{bomaztab}{3}
a & b & W\\
c & d & g\\
e & f & g\\
\end{bomaztab}
\qquad
\begin{bomaztab}{2}
a & W \\
c & g \\
e & g \\
\end{bomaztab}
\medskip
XYZ
\begin{bomaztab}[t]{2}
a & W \\
c & g \\
e & g \\
\end{bomaztab}
\end{document}
稍微不同的实现方式是,从第一行猜测列数;但是,可以明确指定具有不同对齐方式的列,参见最后一个例子;也可以独立设置垂直对齐方式。
\documentclass{article}
\usepackage{xparse,environ}
\ExplSyntaxOn
\NewDocumentEnvironment{bomaztab}{ O{} +b }
{
\bool_set_true:N \l_bomaz_guess_bool
\keys_set:nn { bomaz/tables }
{
valign=c,
#1
}
\bomaz_maketable:VVn \l_bomaz_align_tl \l_bomaz_preamble_tl { #2 }
}
{}
\bool_new:N \l_bomaz_guess_bool
\tl_new:N \l_bomaz_align_tl
\tl_new:N \l_bomaz_preamble_tl
\tl_new:N \l_bomaz_firstrow_tl
\seq_new:N \l_bomaz_body_seq
\seq_new:N \l__bomaz_preamble_seq
\seq_new:N \l__bomaz_temp_seq
\keys_define:nn { bomaz/tables }
{
valign .tl_set:N = \l_bomaz_align_tl,
preamble .code:n =
{
\bool_set_false:N \l_bomaz_guess_bool
\tl_set:Nn \l_bomaz_preamble_tl { #1 }
},
}
\cs_new_protected:Nn \bomaz_maketable:nnn
{
% #1 = alignment argument, #2 = preamble, #3 = body
% split the body at \\
\seq_set_split:Nnn \l_bomaz_body_seq { \\ } { #3 }
% detach the first row
\seq_pop_left:NN \l_bomaz_body_seq \l_bomaz_firstrow_tl
\bool_if:NT \l_bomaz_guess_bool
{
\__bomaz_preamble_guess:
}
\__bomaz_preamble_compute:
% start the tabular
\bomaz_tabular:nV { #1 } \l_bomaz_preamble_tl
% first row is followed by \hline
\l_bomaz_firstrow_tl \\ \hline
% deliver the other rows
\seq_use:Nn \l_bomaz_body_seq { \\ }
% end the tabular
\endtabular
}
% helper function to be varied (start of tabular)
\cs_new_protected:Nn \bomaz_tabular:nn { \tabular[#1]{#2} }
\cs_generate_variant:Nn \bomaz_tabular:nn { nV }
% variant
\cs_generate_variant:Nn \bomaz_maketable:nnn { VVn }
\cs_new_protected:Nn \__bomaz_preamble_guess:
{
\seq_set_split:NnV \l__bomaz_temp_seq { & } \l_bomaz_firstrow_tl
\tl_set:Nx \l_bomaz_preamble_tl
{
\prg_replicate:nn { \seq_count:N \l__bomaz_temp_seq } { l }
}
}
\cs_new_protected:Nn \__bomaz_preamble_compute:
{
\seq_set_split:NnV \l__bomaz_preamble_seq { } \l_bomaz_preamble_tl
\tl_set:Nx \l_bomaz_preamble_tl
{
\seq_use:Nnnn \l__bomaz_preamble_seq { || } { | } { || }
}
}
\ExplSyntaxOff
\begin{document}
\begin{bomaztab}
a & b & W\\
c & d & g\\
e & f & g\\
\end{bomaztab}
\qquad
\begin{bomaztab}
a & W \\
c & g \\
e & g \\
\end{bomaztab}
\medskip
XYZ
\begin{bomaztab}[valign=t,preamble=rl]
aaa & WWW \\
cc & gg \\
e & ggg \\
\end{bomaztab}
\end{document}
答案2
您可以使用类似下面的方法。请注意,将 放在第一行下方的方法\hline
并不美观,恕我直言。
\documentclass[]{article}
\newcount\tabtwocnt
\makeatletter
\newenvironment*{tabular2}[2][]
{%
\def\tabtwotmpa{\begin{tabular}[#1]}%
\ifnum#2=1\relax%
\def\tabtwotmpb{||l}
\else%
\def\tabtwotmpb{}
\tabtwocnt=1\relax%
\loop%
\edef\tabtwotmpb{\tabtwotmpb l|}%
\advance\tabtwocnt by 1\relax%
\ifnum\tabtwocnt<#2\relax%
\repeat%
\edef\tabtwotmpb{\tabtwotmpb|l}
\fi%
\global\let\tabtwotmpc\\
\expandafter\tabtwotmpa\expandafter{\tabtwotmpb}%
\global\let\tabtwotmpd\\%
\gdef\\{\global\let\\\tabtwotmpd\\\hline}\@firstofone%
}{%
\end{tabular}
\global\let\\\tabtwotmpc
}
\makeatother
\begin{document}
\begin{tabular2}[]{1}
a
\end{tabular2}
\begin{tabular2}[]{2}
a & b
\end{tabular2}
\begin{tabular2}[]{3}
a & b & c\\
d & e & f
\end{tabular2}
\begin{tabular2}[]{4}
a & b & c & z\\
d & e & f & z
\end{tabular2}
\begin{tabular2}[]{5}
a & b & c & y &z\\
d & e & f & y &z
\end{tabular2}
\begin{tabular2}[]{12}
a & b & c & y & z & 1 & 2 & 3 & 4 & 5 & 6 & 7\\
a & b & c & y & z & 1 & 2 & 3 & 4 & 5 & 6 & 7\\
a & b & c & y & z & 1 & 2 & 3 & 4 & 5 & 6 & 7
\end{tabular2}
Foo\\Bar
\end{document}
答案3
带有listofitems
和标记列表。不需要列数参数。
\documentclass{article}
\usepackage{listofitems,environ}
\newtoks\tabAtoks
\newtoks\tabAhead
\newcommand\apptotoks[2]{#1\expandafter{\the#1#2}}
\NewEnviron{tabularA}[1][c]{%
\setsepchar{\\/&}%
\readlist\tabA{\BODY}%
\tabAtoks{}%
\foreachitem\i\in\tabA[]{%
\ifnum\listlen\tabA[\icnt]>1\relax%
\tabAhead{}%
\foreachitem\j\in\tabA[\icnt]{%
\ifnum\jcnt=1\relax\else\apptotoks\tabAhead{|}\fi%
\ifnum\jcnt=\listlen\tabA[\icnt]\relax\apptotoks\tabAhead{|}\fi%
\apptotoks\tabAhead{l}%
\ifnum\jcnt=1\relax\else\apptotoks\tabAtoks{&}\fi%
\expandafter\apptotoks\expandafter\tabAtoks\expandafter{\j}%
}%
\ifnum\icnt<\listlen\tabA[]\relax\apptotoks\tabAtoks{\\}\fi%
\ifnum\icnt=1\relax\apptotoks\tabAtoks{\hline}\fi%
\fi%
}%
\def\tmp{\begin{tabular}[#1]}
\expandafter\tmp\expandafter{\the\tabAhead}%
\the\tabAtoks
\end{tabular}
}
\begin{document}
\begin{tabularA}
a & b & W\\
c & d & g\\
e & f & g\\
\end{tabularA}
\qquad
\begin{tabularA}
a & W \\
c & g \\
e & g \\
\end{tabularA}
\medskip
XYZ
\begin{tabularA}[t]
a & W \\
c & g \\
e & g \\
\end{tabularA}
\end{document}
答案4
我使用 TeXstudio 的宏精确地完成了此操作,并且我想大多数编辑器都有类似的宏或片段功能。
在 TeXstudio 中,只需将代码粘贴到框中并为其命名即可:
- 转至
Macros
>Edit Macros
。 - 单击
Add
按钮。 - 将表格模板文本放入
LaTeX Content
字段中,选择Type
=Normal
。 - 在字段中输入您想要在 TeXstudio 菜单上显示的名称
Name
。 - 或者,您可以定义触发文本(
Trigger
字段),当输入时,将插入您的表格模板。
要使用它,请转到Macros
TeXstudio 中的菜单并选择您添加到上面字段的名称Name
。
对于经常使用的项目,我还分配了快捷键组合,因此插入表格、图形或章节标题就像CTRL
+ SHIFT
+T
或其他任何键一样简单:
- 转至
Options
>Configure TeXstudio...
。 - 选择
Shortcuts
选项卡。 - 转到菜单条目
Macro
。 - 展开它并选择您刚刚创建的宏。
- 双击该
Current Shortcut
字段,按下所需的组合键,然后点击ENTER
。
请注意,在 TeXstudio 中,快捷键似乎是位置相关的:如果您将CTRL
+分配Q
给第二个宏“插入酷炫内容”,然后将此宏移动到可编辑列表中的其他位置,则CTRL
+Q
将激活宏列表中第二个位置的内容,而不是“插入酷炫内容”。这是一个奇怪的设计选择,因此您应该注意这一点。
我知道您正在考虑使用 Latex 宏(即\newcommand\whatever
)来实现此目的,但正如通常的情况一样,Latex 使不可能的事情变得简单,使容易的事情变得难以忍受,只有通过深刻理解古代编程或两者兼而有之才能解决。
你的编辑器没有这样的问题;-)
(编辑:考虑到过多的软件包——数千行代码,至少——这些只是为了使基本表格功能在 Latex 中正常工作(按行格式化、多列、扩展单元格、垂直对齐设置,甚至最基本的功能,文字换行,它在我的 Atari 800 上运行良好,没有任何黑客攻击),我坚持我的观点,即必须对古代编程有深入的了解才能完成在其他软件中很容易完成的事情(任何将其视为_
保留字符的语言都是古老的,甚至是史前的)。这并不意味着 Latex 不好,但它可能是任何不在传统银行大型机上工作的人都会遇到的最神秘的东西)。