使用 etoolbox \AtBeginEnvironment 访问传递给环境的参数

使用 etoolbox \AtBeginEnvironment 访问传递给环境的参数

我想etoolbox在表格环境开始时运行一些代码。我想在此代码中使用列规范。这可以轻松完成吗?

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{etoolbox}
\AtBeginEnvironment{tabular}{...I want to do something with 'cc' (or whatever the column spec is)...}
%\AtBeginEnvironment{tabular}{something with #1, not surprisingly this fails}
\begin{document}
\begin{tabular}{cc}
     hello & world  \\
\end{tabular}
\end{document}

答案1

我做了一些探索,试图找出使用这样的钩子时,哪些标记按什么顺序执行,并诊断性地打印\addmeafter出前 2 个(跟在我的参数后面)。第二个诊断标记是 key: \csname。这意味着后面是环境名称,并且长度可变。因此,我所做的是扩展\csname并将相同的标记序列传递给\zzz。通过扩展它一次,我的参数(又名)后面的第二个标记#3不再是\csname,而是\zz\tabular。因此,通过将我想要的#1参数放在后面#3,它就会被放置得好像它是环境中的第一个东西一样。

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{etoolbox}
\newcommand\addmeafter[3]{(\detokenize{#2!#3!})\par% <--FOR DIAGNOSIS
  \def\tmp{\zzz{#1}}\expandafter\tmp\expandafter#2#3}
\newcommand\zzz[3]{#2#3#1}
\newenvironment{zz}{[}{]}
\AtBeginEnvironment{zz}{\addmeafter{Q}}
\AtBeginEnvironment{tabular}{\addmeafter{{|c|c|}}}
\begin{document}
\begin{zz}
     hello  world
\end{zz}

\bigskip
\begin{tabular}
\hline
a & b\\ 
\hline
c&d\\
\hline
\end{tabular}
\end{document}

在此处输入图片描述

如果我注释掉诊断信息,并将钩子作为宏实现\tabcols

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{etoolbox}
\newcommand\addmeafter[3]{%(\detokenize{#2!#3!})\par% <--FOR DIAGNOSIS
  \def\tmp{\zzz{#1}}\expandafter\tmp\expandafter#2#3}
\newcommand\zzz[3]{#2#3#1}
\newenvironment{zz}{[}{]}
\AtBeginEnvironment{zz}{\addmeafter{Q}}
\AtBeginEnvironment{tabular}{\addmeafter{{\tabcols}}}
\begin{document}
\begin{zz}
     hello  world
\end{zz}

\bigskip
\def\tabcols{|c|c|}
\begin{tabular}
\hline
a & b\\ 
\hline
c&d\\
\hline
\end{tabular}

\bigskip
\def\tabcols{|c|c|c|}
\begin{tabular}
\hline
a & b & xxx\\ 
\hline
c&d& y\\
\hline
\end{tabular}
\end{document}

tabular我得到了想要的结果,允许我在宏中预先指定列格式\tabcols,而不是在执行时指定它。

在此处输入图片描述


补充

正如唐纳所说,我可能误解了这个问题。

如果不想坚持使用列规范,而只是提前读取它,则更改很简单。在这里,我#4在 中读取列规范,\zzz并将其作为参数传递给#1(即宏\tabcols),然后执行tabular #3

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{etoolbox}
\newcommand\readafter[3]{%
  \def\tmp{\zzz{#1}}\expandafter\tmp\expandafter#2#3}
\newcommand\zzz[4]{#1{#4}#2#3{#4}}
\newcommand\tabcols[1]{%
  The spec for the next tabular will be \detokenize{#1}\par}
\AtBeginEnvironment{tabular}{\readafter\tabcols}
\begin{document}

\begin{tabular}{|c|c|}
\hline
a & b\\ 
\hline
c&d\\
\hline
\end{tabular}


\bigskip
\begin{tabular}{|c|c|c|}
\hline
a & b & xxx\\ 
\hline
c&d& y\\
\hline
\end{tabular}
\end{document}

在此处输入图片描述

双倍补充

OP 在评论中询问tabular*tabularx。我将展示如何解决 的两个强制参数tabular*。它与上述解决方案的逻辑相同,但吸收了一个进一步的论点。例如,与 进行比较\readafter\readtwoafter然后与 进行比较\zzz\zzzz最后与 进行\tabcols比较\tabstarinputs

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{etoolbox}
\newcommand\readafter[3]{%
  \def\tmp{\zzz{#1}}\expandafter\tmp\expandafter#2#3}
\newcommand\readtwoafter[3]{%
  \def\tmp{\zzzz{#1}}\expandafter\tmp\expandafter#2#3}
\newcommand\zzz[4]{#1{#4}#2#3{#4}}
\newcommand\zzzz[5]{#1{#4}{#5}#2#3{#4}{#5}}
\newcommand\tabcols[1]{%
  The spec for the next tabular will be \detokenize{#1}\par}
\newcommand\tabstarinputs[2]{%
  The width for the next tabular* will be \detokenize{#1}\par
  The spec for the next tabular* will be \detokenize{#2}\par}
\AtBeginEnvironment{tabular}{\readafter\tabcols}
\AtBeginEnvironment{tabular*}{\readtwoafter\tabstarinputs}
\begin{document}

\begin{tabular}{|c|c|}
\hline
a & b\\ 
\hline
c&d\\
\hline
\end{tabular}


\bigskip
\begin{tabular}{|c|c|c|}
\hline
a & b & xxx\\ 
\hline
c&d& y\\
\hline
\end{tabular}

\bigskip
\begin{tabular*}{2in}{|c|c||}
\hline
a & big list of stuff here\\ 
\hline
c&d\\
\hline
\end{tabular*}

\end{document}

在此处输入图片描述

答案2

传递给的强制参数tabular实际上是由另一个宏内部吸收的,因此很难自然地获取它。但是,你可以重新定义tabular以使用以下方法获取该参数environ或者只是通过重新定义初始来进行干预\tabular

在此处输入图片描述

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage{tabularx}

\let\oldtabular\tabular
\expandafter\let\expandafter\oldtabulars\csname tabular*\endcsname
\expandafter\let\expandafter\endoldtabulars\csname endtabular*\endcsname

\RenewDocumentCommand{\tabular}{ O{c} m }{%
  Do something with \detokenize{#2} \par
  \oldtabular[#1]{#2}}
\RenewDocumentEnvironment{tabular*}{ m O{c} m }{%
  Do something with \detokenize{#3} \par
  \begin{oldtabulars}{#1}[#2]{#3}
}{%
  \end{oldtabulars}%
}

\begin{document}

\begin{tabular}{c|c}
  hello & world
\end{tabular}

\hrulefill

\begin{tabular*}{.5\linewidth}{c|c|c}
  hello & world & star
\end{tabular*}

\hrulefill

\begin{tabularx}{.5\linewidth}{c|c|X}
  hello & world & tabularx
\end{tabularx}

\end{document}

上述示例提供了管理tabulartabular*tabularx.内部tabularx使用tabular*,因此无需执行任何其他操作。

相关内容