4

I would like to use etoolbox to run some code at the beginning of the tabular environment. I would like to use the column specification in this code. Can this be done easily?

\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}
8
  • It would be nice to know what you want to do with cc.
    – egreg
    Commented Apr 14, 2021 at 20:31
  • Good point--I was going to use it for a Lua function, no "printing" of the cc required. Being familiar with your posts, I suspect you'd provide an expl3 solution :) Commented Apr 14, 2021 at 20:37
  • Still we don't know what your real aim is. What would you pass and what are you going to do with it?
    – egreg
    Commented Apr 14, 2021 at 20:59
  • @egreg I was planning on using it to count the total number of columns in the tabular. I found a nice solution here, but I wanted to try it another way--I also feel that 'looking at' environment arguments could be useful in other scenarios. tex.stackexchange.com/questions/418427/… Commented Apr 14, 2021 at 21:11
  • You can't count columns by simply looking at this argument. It is easy to define a new column type which contains more than one column declarations. Commented Apr 15, 2021 at 5:36

2 Answers 2

4

I did a little poking around trying to figure out what tokens are executed in what order with such a hook, and diagnostically print the first 2 (that follow my \addmeafter argument) out. The second diagnostic token is key: \csname. That means what follows is the environment name and is of variable length. Thus, what I do is expand the \csname and pass the same sequence of tokens to \zzz. By expanding it once, the 2nd token following my argument (aka #3) is no longer \csname, but \zz or \tabular. Thus, by placing my desired #1 argument following #3, it gets placed as if it were the first thing in the environment.

\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}

enter image description here

If I comment out my diagnostics, and implement the hook as a macro \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}

I get the desired result, allowing me to pre-specify the tabular column format in the macro \tabcols, and not specify it at the time of execution.

enter image description here


SUPPLEMENT

On the possibility, as Don suggests, that I misread the question..

If it is not desired to stick in a column specification, but merely to read it in advance, the change is straightforward. Here I read the column specification, #4 in \zzz, and pass it as an argument to #1 (which is the macro \tabcols), in advance of executing the 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}

enter image description here

DOUBLE SUPPLEMENT

The OP asks in a comment about tabular* and tabularx. I will show how to address the two mandatory arguments of tabular*. It is the same logic as the above solutions, but taken to absorb one further argument. For example, compare \readafter to \readtwoafter, then compare \zzz to \zzzz and finally compare \tabcols to \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}

enter image description here

10
  • 2
    you shouldn't use \zzz. That's identity theft ;-) Commented Apr 14, 2021 at 18:47
  • 1
    @UlrikeFischer If you steal a little, it's plagiarism. If you steal enough, it's research! -Tom Lehrer Commented Apr 14, 2021 at 18:48
  • 1
    @DonHosek I have added a SUPPLEMENT to address your comment Commented Apr 14, 2021 at 19:19
  • 1
    @likethevegetable I don't understand lua, but I did provide a DOUBLE SUPPLEMENT that addresses the tabular* question. Gotta go. Perhaps tabularx exercise is left to the reader. Commented Apr 14, 2021 at 20:26
  • 1
    @likethevegetable: I've updated my answer to manage column specification for tabular, tabular* and tabularx.
    – Werner
    Commented Apr 14, 2021 at 21:21
3

The mandatory argument passed to tabular is really absorbed by another macro internally, so it's difficult to grab it naturally. You can, however, redefine tabular to grab that argument using environ, or just intervene by redefining the initial \tabular:

enter image description here

\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}

The above examples provides the option to manage the column specification for tabular, tabular* and tabularx. tabularx uses tabular* internally, so no need to do anything else.

2
  • Great stuff. Why is plain tabular renewed as a command and not enviro? Also, why the abc counter? Commented Apr 15, 2021 at 1:49
  • @likethevegetable: Forgot the abc counter as part of debugging. And, it's actually needless to redefine tabularx since it uses tabular* internally. I've updated the answer to note that. It's easier to redefine tabular* as an environment, otherwise you'll have to do more \csname...\endcsname trickery to redefine the command, because you can't just do \renewcommand{\tabular*}{...}.
    – Werner
    Commented Apr 15, 2021 at 4:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .