我有如下命令:
\newcommand{\Comment}[1]{&&\tabularnewline\hline}
现在我想将其转换为如下环境:
\newsavebox{\tempDescription}
\newenvironment{Description}
{%
\begin{lrbox}{\tempDescription}%
\ignorespaces%
}
{%
\end{tempDescription}%
&&&\usebox{\tempDescription}\tabularnewline\hline%
}
完整代码如下:
\documentclass[dvips,dvipsnames,rgb,table]{book}
\usepackage[a4paper,hmargin=10mm,vmargin=40mm,showframe]{geometry}
\usepackage{longtable}
\usepackage{array}
\usepackage{calc}
\usepackage{lscape}
\setlength{\tabcolsep}{10pt}
\setlength{\arrayrulewidth}{1pt}
\newcounter{No}
\renewcommand{\theNo}{\arabic{No}}
\newenvironment{MyTable}[4]%
{%
\newcolumntype{O}[1]%
{%
>{%
\begin{minipage}%
{%
##1\linewidth-2\tabcolsep-1.5\arrayrulewidth%
}%
\vspace{\tabcolsep}%
}%
c%
<{%
\vspace{\tabcolsep}%
\end{minipage}%
}%
}%
\newcolumntype{I}[1]%
{%
>{%
\begin{minipage}%
{%
##1\linewidth-2\tabcolsep-\arrayrulewidth%
}%
\vspace{\tabcolsep}%
}%
c%
<{%
\vspace{\tabcolsep}%
\end{minipage}%
}%
}%
\setcounter{No}{0}%comment out this if you want to continuous numbering for all tables.
\begin{longtable}%
{%
|>{\stepcounter{No}\centering\scriptsize\theNo}O{#1}<{}%
|>{\centering}I{#2}<{\input{\jobname.tmp}}%
|>{\centering\lstinputlisting{\jobname.tmp}}I{#3}<{}%
|>{\scriptsize}O{#4}<{}%
|%
}%
\hline\ignorespaces%
}%
{%
\end{longtable}%
}
\newcommand{\Comment}[1]{&&\tabularnewline\hline}
\newsavebox{\tempDescription}
\newenvironment{Description}
{%
\begin{lrbox}{\tempDescription}%
\ignorespaces%
}
{%
\end{tempDescription}%
&&&\usebox{\tempDescription}\tabularnewline\hline%
}
\usepackage{listings}
\lstset{%
language={PSTricks},
breaklines=true,
basicstyle=\ttfamily\scriptsize,%
keywordstyle=\color{blue},
backgroundcolor=\color{yellow!30}%
}
\usepackage{fancyvrb}
\def\MyRow{%
\VerbatimEnvironment%
\begin{VerbatimOut}{\jobname.tmp}%
}
\def\endMyRow{%
\end{VerbatimOut}%
}
\usepackage{pstricks,pst-node}
\newpsstyle{gridstyle}{%
gridwidth=0.4pt,%default: 0.8pt
gridcolor=Red!20,%default: black
griddots=0,%default: 0
%
gridlabels=3pt,%default: 10pt
gridlabelcolor=Blue,%default: black
%
subgriddiv=5,%default: 5
subgridwidth=0.2pt,%default: 0.4pt
subgridcolor=Green!20,%default: gray
subgriddots=0%default: 0
}
\usepackage{lipsum}
\begin{document}
%\clearpage
%\pagestyle{empty}
%Landscape starts here.
%\begin{landscape}
\arrayrulecolor{Red}
\begin{MyTable}{0.05}{0.3}{0.3}{0.35}%
%=============
\begin{MyRow}
\pspicture*[showgrid](3,3)
\pnode(1,1){A}
\pnode(3,3){B}
\ncline{A}{B}
\endpspicture
\end{MyRow}
\Comment{\lipsum[1]}
%=============
\begin{MyRow}
\begin{pspicture}[showgrid](3,3)
\psframe*[linecolor=red!30](3,2)
\end{pspicture}
\end{MyRow}
\Comment{\lipsum[2]}
%=============
\begin{MyRow}
\pspicture[showgrid](3,3)
\psframe*[linecolor=green!30](3,2)
\endpspicture
\end{MyRow}
\Comment{\lipsum[3]}
%=============
\begin{MyRow}
\pspicture[showgrid](3,3)
\psframe*[linecolor=Yellow](3,2)
\endpspicture
\end{MyRow}
\Comment{%
\begin{equation}
\int_a^b f(x)\, \textrm{d}x=F(b)-F(a)
\end{equation}
is the fundamental theorem of calculus.
}
%=============
\begin{MyRow}
\pspicture[showgrid](3,3)
\psframe*[linecolor=Maroon!30](3,2)
\endpspicture
\end{MyRow}
\begin{Description}%{%
Today I ate burnt bread. It was so delicious.
\begin{equation}
\int_a^b f(x)\, \textrm{d}x=F(b)-F(a)
\end{equation}
is the fundamental theorem of calculus.
%}
\end{Description}
%=============
\end{MyTable}
%\end{landscape}
%Landscape stops here.
%\pagestyle{plain}
\end{document}
为什么无法转换?
答案1
快速回答:
\usepackage{environ}
\NewEnviron{Description}{%
\expandafter\gdef\expandafter\gtemp\expandafter{%
\expandafter&\expandafter&\expandafter&\BODY\tabularnewline\hline
}%
\aftergroup\gtemp
}
它不允许逐字文本,但该包cprotect
可以修复这个问题。我第一次尝试直接接受逐字文本,但使用 lrbox 只允许单行框(不完全正确)。
我们使用 Will Robertson 的environ
包来定义Description
环境。它读取环境的全部内容(直到达到\end{Description}
)并将其存储在中\BODY
。天真地,我们希望
\NewEnviron{Description}{%
&&&\BODY\tabularnewline\hline}
但是这失败了:&&&\BODY\tabularnewline\hline
在组内创建,整个过程的行为有点像{&&&\BODY...}
而不是&&&\BODY...
。我们想将&
移出组。这可以使用\aftergroup
原语来完成:{...\aftergroup\a}
给出{...}\a
,即\a
在组完成后执行。
因此,我们将要执行的操作存储在命令中,\gtemp
然后执行\aftergroup\gtemp
。因此,你会认为正确的代码是
\NewEnviron{Description}{%
\gdef\gtemp{%
&&&\BODY\tabularnewline\hline
}%
\aftergroup\gtemp
}
但它是不是结束。\BODY
当我们在组内时,它只是我们环境的主体。当我们尝试&&&\BODY\tabularnewline\hline
在组外执行时,我们得到一个错误:\BODY
没有定义。我们该怎么办?我们需要\BODY
用它的替换扩张(定义)我们仍在组内。对于这种使用\expandafter
,这非常实用,但使用起来很麻烦。它告诉 TeX“看到下一个标记了吗?好吧……等等,先执行(扩展)下一个”。典型的构造是\expandafter\a\expandafter\b\expandafter\c\expandafter\d\e
。第一个\expandafter
读取\a
,并扩展下一个标记\expandafter
。第二个\expandafter
看到\b
,但首先扩展\expandafter
,等等。最后,\e
首先扩展,然后是,,,\a
。(各种标记不会重新排序:只有它们扩展的方式会发生变化。)\b
\c
\d
因此,在我们的最终代码中,我在这里重复一遍,
\usepackage{environ}
\NewEnviron{Description}{%
\expandafter\gdef\expandafter\gtemp\expandafter{%
\expandafter&\expandafter&\expandafter&\BODY\tabularnewline\hline
}%
\aftergroup\gtemp
}
我们首先展开\BODY
,然后\gdef\gtemp{&&&
身体\tabularnewline\hline}
, 在哪里身体是环境的真实内容(\BODY
已展开)。最后,\aftergroup\gtemp
上面的解释会将其放在表格流中的正确位置。
答案2
由于 TeX 解析参数以进行对齐的方式(这是表格的基础技术),您所做的工作不起作用。在决定将什么放入表格单元格时,TeX 会读取一个启用宏扩展的标记,检查是否存在特殊情况,例如\span
,然后扫描不启用宏扩展的文本,直到下一个&
或\cr
标记。它找到的内容会放入表格单元格,然后以通常的方式进行处理,包括宏扩展和所有内容。
您的问题是,\begin{Description}
在执行 之前会进行各种设置\Description
,特别是\Description
在 TeX 遇到由扩展 产生的第一个不可扩展标记之前不会进行扩展\begin
。因此 TeX 看不到&
其中的标记,并假设它们全部进入单个表格单元格。