我的最终目标是创建自己的表格状环境,其中所有条目默认都处于数学模式,我们称之为fancytable
。(一个要求是第一列与其他列之间要有一条线隔开,但这不应该是主要问题。)
在表格中的数学模式无需到处使用 $...$我找到了解决这个问题的方法:
\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\begin{document}
\begin{tabular}{ >{$}c<{$} | >{$}c<{$} >{$}c<{$} }
x & x^2 & x^3\\
y & y^2 & y^4
\end{tabular}
\end{document}
但这不是我想要的。(请注意,我之所以包括tabularx
它,是因为我需要它用于其他目的,我认为值得一提。)表格可能会变得很大(比如 15 列),因此>{$}c<{$}
每次写入都会很乏味。此外,有一天我可能会改变主意并选择另一种布局,而更改所有表格并不是我真正期待的事情。这就是为什么我尝试使其成为一个环境。
最近我问了几次如何复制和打印字符串,在将字符串连接任意次数的命令。因此,目前我有一个可用的命令\repeatstring
,我希望像在 中那样需要它\repeatstring{5}{>{$}c<{$}}
。(我已在下面包含了其当前定义)
我尝试的第一件事是
\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
% definition of \repeatstring left out, see below
\newenvironment{fancytable}[1]%
{\begin{tabular}{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} } }
{\end{tabular}}
\begin{document}
\begin{fancytable}{2} % the argument of fancytable is 1 less than the desired number of columns
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}
但tabular
不接受其标头中的任意命令。我读过如何将宏扩展为表格头?并尝试调整那里给出的答案。同时,我发现我应该以某种方式扩展它,\repeatstring
看看tabular
它脑子里在想什么。我认为columntype
每次fancytable
创建 a 时都定义一个新的并不是一个好主意(无论如何我都做不到,得到了与上述方法相同的错误)。一些尝试:
\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
% definition of \repeatstring left out, see below
\newcommand\buildtabularhead{}
\newenvironment{fancytable}[1]%
{%
\renewcommand\buildtabularhead{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%
\expandafter\tabular\expandafter{\buildtabularhead}}
{\endtabular}
\begin{document}
\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}
(基于 Matthew Leingang 的回答)但我一直
包数组错误:非法前缀标记(\repeatstring):使用了‘c’。
和往常一样。Bruno Le Floch 的回答也一样:
\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
% definition of \repeatstring left out, see below
\makeatletter
\newcolumntype{\expand}{}
\long\@namedef{NC@rewrite@\string\expand}{\expandafter\NC@find}
\makeatother
\newcommand\mypream{}
\newenvironment{fancytable}[1]%
{%
\renewcommand\mypream{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%
\begin{tabular}{\expand\mypream}}
{\endtabular}
\begin{document}
\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}
我真的不知道该怎么办。我读何时使用 \edef、\noexpand 和 \expandafter?但没有达到正确的使用\expandafter
方式\edef
。我总是和
包数组错误:非法的前导标记(\repeatstring 或 \edef 或 \expandafter 或 \setcounter):使用了‘c’。
\setcounter
来自于我当前\repeatstring
扩展它时的定义:
\usepackage{etoolbox}
\newcounter{countdown}
\newcommand\concathere{}
\newcommand\repeatstring[2]{
\setcounter{countdown}{#1}
\renewcommand\concathere{}
\whileboolexpr{test {\ifnumcomp{\thecountdown}{>}{0}}}{
\addtocounter{countdown}{-1}
\appto\concathere{#2}
}
\concathere
}
答案1
最好的解决办法是简单地“重复n-times' 在tabular
序言中确实是使用 *
如下语法barto 的回答但是,如果你出于某种原因想要使用包含前言的宏,可以使用布鲁诺的解决方案到如何将宏扩展为表格头?,那么重要的是确保它包含确切地序言文本。这需要一个\repeatstring
可扩展的定义,并使用\edef
类似扩展的代码
\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\usepackage{xparse}
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\repeatstring}{mm}
{
\prg_replicate:nn { #1 } { #2 }
}
\ExplSyntaxOff
\makeatletter
\newcolumntype{\expand}{}
\long\@namedef{NC@rewrite@\string\expand}{\expandafter\NC@find}
\makeatother
\newcommand\mypream{}
\makeatletter
\newenvironment{fancytable}[1]%
{%
\protected@edef\mypream{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%
\begin{tabular}{\expand\mypream}}
{\end{tabular}}
\makeatother
\begin{document}
\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}
在上面,我使用了一个expl3
基于扩展的重复函数来定义\repeatstring
(与egeg 的解决方案到将字符串连接任意次数的命令),这意味着当\protected@edef
应用时\mypream
最终得到定义>{$}c<{$} | >{$}c<{$}>{$}c<{$}
,IE这正是tabular
序言中所需要的。
所有这些都是必要的,因为array
可以避免任何tabular
前言的扩展。因此,如果你这样做
\renewcommand\mypream{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%
看到array
的正是:不是一串重复的>{$}c<{$}
条目,而是不认识的标记\repeatstring
(因此引发错误)。
答案2
c
按照>$c<$
此处的要求,在表格中替换为基本上就是定义array
环境。此外,声明比使用的更多的列也没有坏处,因此列数参数实际上并不需要,只需声明一个大数字(此处为 50)
\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\newenvironment{fancytable}
{$\begin{array}{c| * {50} {c} } }
{\end{array}$}
\begin{document}
\begin{fancytable}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}
答案3
感谢 Daniel 的建议,\repeatstring
这里就不需要了。
\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\newenvironment{fancytable}[1]%
{\begin{tabular}{>{$}c<{$} | * {#1} {>{$}c<{$}} } }
{\end{tabular}}
\begin{document}
\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}
答案4
还有另一种方法:直接使用\halign
原语。请注意以下特点\halign
:
\halign{first:#. && rep:# \cr
a& b& c& d& e \cr
u& v& w& x& y \cr}
创建:
first:a. rep:b rep:c rep:d rep:e
first:u. rep:v rep:w rep:x rep:y
换句话说:您不需要在声明部分中声明所有列\halign
。如果实际列更多,则处理将返回到标记&&
,并一次又一次地读取声明部分...
你的实现fancytable
可以看起来像这样:
\documentclass{article}
\newenvironment{fancytable}
{\vbox\bgroup\offinterlineskip \let\\=\cr
\halign\bgroup$##$\ \vrule height2ex depth1ex &&\ $##$\ \cr}
{\crcr\egroup\egroup}
\begin{document}
\begin{fancytable}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}
不需要特殊的包。第一列由
$##$\ \vrule height2ex depth1ex
声明部分和任意数量的下一列由
\ $##$\
有时,了解 TeX 原语是有用的。