# How to apply a macro to each column of a table

I want to apply a macro to all the cells of a column with the cell content as the input to the macro. Is this possible?

For example if the cell contents have the word TEST, the macro should take TEST as its argument.

-

It should be as simple as:

\def\mymacro#1{\lowercase{#1}}
\halign{&\mymacro{#}\cr
HELLO&WORLD\cr
TEST&123\cr}
\bye


For Yiannis's comment to apply the macro only to the first column, change the preamble (&\mymacro{#}\cr) to \mymacro{#}&&#\hfil\cr, for example. An ampersand at the very beginning tells TeX to repeat the definition(s) for every column, whereas && defines that the following column definitions should be repeated.

Ofcourse, you don't need to repeat anything if you don't want to.

-
@morsburg I am not very familiar with TeX's tables, how would you apply the macro only on the first column? –  Yiannis Lazarides Mar 4 '11 at 12:17
@Yiannis: I've updated the answer to include a solution for your question. BTW, my handle is morbusg, not morsburg. –  morbusg Mar 4 '11 at 12:41
@morbusg: Very nice plainTeX solution! Thank you very much for explaining the things about repeating column definitions in the preamble. I didn't know about them yet. –  Martin Scharrer Mar 4 '11 at 12:46
@morbusg thanks for posting the additional comments. Sorry for the "burg", I spent too many years in South Africa! –  Yiannis Lazarides Mar 4 '11 at 18:15
@Martin: In my opinion, morbusg's answer shows that plain TeX tables are great! No need for any package. (No offense meant :-)) Can't you just do this in collcell somehow? @morbusg: +1, nicely written up answer! –  Hendrik Vogt Mar 6 '11 at 8:16

You can use the relatively new collcell package to collect the cell content and feed it to a macro of your choice. It uses the array package to place code before and after each cell.

\documentclass{article}
\usepackage{collcell}
\usepackage{array}% actually already loaded by collcell
\newcommand*{\mymacro}[1]{\fbox{#1}}% Do anything you like with #1
\newcolumntype{C}{>{\collectcell\mymacro}c<{\endcollectcell}}

\begin{document}

\begin{tabular}{CC}
TestA  & A longer test cell \\
\empty & The new version supports 'verb'! \\
\end{tabular}

\end{document}


Make sure you use the version 2011/02/27 (or later) which contains a lot of improvements.

There is also the possibility to do it the following way, which compiles faster than collcell but does not work in the last cell of each row. It reads everything between the internally used macros \ignorespaces and \unskip. I got this from Ulrike Fischer on de.c.t.t a while ago.

\documentclass{article}
\usepackage{array}
\newcommand*{\mymacro}[1]{\fbox{#1}}

\def\simplecollect#1#2\ignorespaces#3\unskip{#1{#3}\unskip}
\newcolumntype{S}{>{\simplecollect\mymacro}c}

\begin{document}

\begin{tabular}{Sc}
TestA  & Doesn't work in the last cell \\
\empty & Sorry!  \\
\end{tabular}

\end{document}

-
Nice solution! –  Yiannis Lazarides Mar 4 '11 at 10:33
@Yiannis: Thanks. I needed this once for my tikz-timing package and then started to code collcell. Ironically, tikz-timing now simply removes \ignorespaces and uses \unskip or \\  as end-marker, so it doesn't need collcell :-) –  Martin Scharrer Mar 4 '11 at 10:37
Thank you very much for collcell. Compared with \ignorespaces…\unskip, it has several advantages, including stripping off trailing whitespace (I wanted to use the content of the cell as a label) and not causing errors when encountering \noalign in a tabularx environment (that may not be the exact issue, I stopped debugging because collcell just works). –  Gilles Dec 27 '13 at 18:47

You can do this by using the array package and defining a \newcolumntype.

For example we can define a macro \test that can take a parameter as its argument and capitalize it.

\def\test#1 {\uppercase{#1}}


We can then define a new column type as:

\newcolumntype{D}{>{\test}l<{.}}


and our minimal example would be:

\documentclass{article}
\usepackage{array}
\begin{document}
\def\test#1 {\uppercase{#1}}
\newcolumntype{D}{>{\test}l<{.}}
\begin{tabular}{DD}
test &test \\
other &test \\
\end{tabular}
\end{document}


Please note that this approach involves delimited macros, in this case the space after the word in the table acts to tell the command that it must only read up to there and obviously will fail if there are more than one word as Martin pointed out. One could use other types of delimiters perhaps a . or a !.

-
This doesn't work in the general case. Here \test reads everything to the first space as argument. So cells with more than a single word or such not ending in a space will fail. –  Martin Scharrer Mar 4 '11 at 6:07

EDIT: added support for \multicolumn.

This solution is more or less a LaTeX version of @morbusg's plain TeX answer. \span forces the expansion of the next token when TeX reads the preamble. \@gobbletwo removes the tokens forming the normal preamble which is inserted by {tabular}: this way, we move the # (i.e. body of the cell) to the middle of what >{...} inserts, rather than after it. More explanations after the code.

\documentclass{article}
\usepackage{array}

\makeatletter
\def\KWP@safe@newline{%
\iffalse{\fi
\let\KWP@old@newline\\%
\let\\\cr
\iffalse}\fi
}
\def\KWP@restore@newline{\iffalse{\fi\let\\\KWP@old@newline\iffalse}\fi}

\newcolumntype{\arg}[1]{%
>{\KWP@safe@newline
#1{\ignorespaces \@sharp\unskip}%
\KWP@restore@newline
\span\@gobbletwo}%
c}

\newcolumntype{\argmulti}[1]{%
>{\KWP@safe@newline
#1{\ignorespaces \@sharp\unskip}%
\KWP@restore@newline
\@gobbletwo}%
c}

\makeatother

\begin{document}

First test.
\begin{tabular}{c\arg{\textbf}}
abc & bcd \\
cde & def \\
\end{tabular}

\bigskip

\newcommand{\mymacro}[1]{#1: $(#1)^{#1}$}%
Second test.
\begin{tabular}{|\arg{\mymacro}|c|}
abc & bcd \\
cdefgh & A\\
\multicolumn{2}{|c|}{ABC}\\
\end{tabular}

\bigskip

\begin{tabular}{|c|c|}
abc & bcd \\
cdefgh & A\\
\multicolumn{2}{|\argmulti{\mymacro}|}{ABC}\\
\end{tabular}

\end{document}


To give an idea of what's going on, let's look at the preamble constructed in the case of the column specification \arg{\textbf}. The "new" part is between \KWP@safe@newline and \@gobbletwo three lines below.

\KWP@safe@newline saves \\, and lets it to \cr. Otherwise, the macro, looking for an argument, would grab everything until the end of the cell, without expanding, and would not see the \cr hidden in the definition of \\. We'll restore the former definition with \KWP@restore@newline.

\textbf{\ignorespaces \@sharp \unskip} is just our macro. \ignorespaces and \unskip remove spaces from the argument (a better way would trim spaces expandably and pass the argument to \textbf), and \@sharp is let to #, which represents the body of the cell.

Finally, \span\@gobbletwo expands when the preamble is read (i.e., earlier than everything else here), and removes the \@sharp (and \ignorespaces, which I don't care about).

\@preamble ->\ialign \bgroup \unhcopy \@arstrutbox
\hskip \col@sep \hfil
\d@llarbegin
\KWP@safe@newline
\textbf {\ignorespaces \@sharp \unskip }%
\KWP@restore@newline
\span \@gobbletwo \ignorespaces \@sharp \unskip \relax
\d@llarend
\hfil \hskip \col@sep
\tabskip \z@ \cr


Caveat: if the last column specifier is that \arg, then the last line of the tabular must be terminated with \\ (or \cr or \crcr).

-
@Bruno thanks! I don't understand much of the code, but it works nicely. –  Chuang Mar 7 '11 at 20:31
@Bruno: Great code! However I have difficulties to use this column type with \multicolumn. –  Martin Scharrer Mar 28 '11 at 11:15
@Martin: thanks. What exactly do you expect of e.g. \begin{tabular}{\arg{\mymacro}c} a&b\\ \multicolumn{2}{|c|}{cde} \\ \end{tabular}? –  Bruno Le Floch Mar 28 '11 at 15:29
@Bruno: No I meant using \arg in the second argument of \multicolumn doesn't work. –  Martin Scharrer Mar 28 '11 at 15:34
@Martin: done. See my update. A matter of removing \span and adding some \iffalse{\fi... \iffalse}\fi. –  Bruno Le Floch Mar 28 '11 at 16:27

Perhaps analogous to @Martin's answer, you can box the cell contents using an lrbox environment, and then supply the boxed contents to your macro:

\documentclass{article}
\usepackage{array}% http://ctan.org/pkg/array
\begin{document}
\newsavebox{\mybox}
\begin{tabular}{c>{\begin{lrbox}{\mybox}}c<{\end{lrbox}\fbox{\usebox\mybox}}c}
One & Two & Three \\ \hline
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9 \\ \hline
\end{tabular}
\end{document}


The array package provides the means to insert content before >{...} and after <{...} a specific column. In this case, the lrbox environment start and end, as well as the resulting macro application for typesetting the cell content after boxing.

The restriction is mainly reliant on what can be boxed by the lrbox environment.

-