展开带有表格头中的参数的宏

展开带有表格头中的参数的宏

我的最终目标是创建自己的表格状环境,其中所有条目默认都处于数学模式,我们称之为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 的回答)但我一直

包数组错误:非法前缀标记(\rep​​eatstring):使用了‘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。我总是和

包数组错误:非法的前导标记(\rep​​eatstring 或 \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 原语是有用的。

相关内容