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.
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.
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}
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.
morbusg, not morsburg.
– morbusg
Mar 04 '11 at 12:41
:-)) Can't you just do this in collcell somehow? @morbusg: +1, nicely written up answer!
– Hendrik Vogt
Mar 06 '11 at 08:16
array to not only have > and < to add material before and after the # in the internal \halign preamble, but actually insert full column description as one expression like \mymacro{#} above. However, it's not that simple to do.
– Martin Scharrer
Mar 06 '11 at 10:46
array package that doesn't have < and >?
– Hendrik Vogt
Mar 06 '11 at 11:41
> and < are fine, it just needs another character which allows to insert both sides of the code at the same time.
– Martin Scharrer
Mar 06 '11 at 12:08
#, then > and < are no longer needed. In fact, you're back to the plain TeX syntax, which I like best!
– Hendrik Vogt
Mar 06 '11 at 13:23
>/< characters even if you have access to #.
– Martin Scharrer
Mar 06 '11 at 13:27
>{...} and gobbling the hash which represents the cell body in the preamble (see below). But in general @morbusg's approach (and my adaptation to LaTeX) forces the user to explictly write something (e.g. \cr, \crcr, \\) at the end of the last line of the tabular if the last column is of the type that takes arguments.
– Bruno Le Floch
Mar 07 '11 at 20:27
\\ in the end of the last row. It's a hassle if you keep swapping rows ...
– Hendrik Vogt
Mar 07 '11 at 21:27
\def\mymacro#1{\lowercase{#1}} \tabskip=0pt \halign to .5\hsize{ \vrule\tabskip=4pt#&\mymacro{#}\tabskip=0pt plus 1fil\strut&#\tabskip=4pt&\vrule#\cr &HELLO & WORLD&\cr &TEST & My number 123&\cr }?
– Ahmed Musa
May 05 '11 at 11:21
\mymacro? The #-symbol inside the preamble represents the stuff that gets inserted into the alignment, so if you mean applying the macro, then by changing the plain # by \mymacro{#} will change that column. If you meant repeating, then, well, I find it more productive to first just construct the preamble without repeats, and only if it's instantly apparent one could use repeats, to use them. I cannot instantly see how to repeat your example because of the fil and vrules.
– morbusg
May 06 '11 at 06:41
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 !.
\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 04 '11 at 06: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).
\multicolumn.
– Martin Scharrer
Mar 28 '11 at 11:15
\begin{tabular}{\arg{\mymacro}c} a&b\\ \multicolumn{2}{|c|}{cde} \\ \end{tabular}?
– Bruno Le Floch
Mar 28 '11 at 15:29
\arg in the second argument of \multicolumn doesn't work.
– Martin Scharrer
Mar 28 '11 at 15:34
\span and adding some \iffalse{\fi... \iffalse}\fi.
– Bruno Le Floch
Mar 28 '11 at 16:27
\arg{\macro} in \multicolumn, since this preamble is only used once??
– Bruno Le Floch
May 01 '11 at 05:48
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.
An alternative solution with tblr environment of tabularray package:
\documentclass{article}
\usepackage{tabularray}
\newcommand{\mycmda}[1]{\fbox{#1}}
\newcommand{\mycmdb}[1]{\underline{#1}}
\begin{document}
\begin{tblr}{Q[c,cmd=\mycmda]Q[c,cmd=\mycmdb]}
Alpha & Gamma \
Beta & Delta \
\end{tblr}
\end{document}
tikz-timingpackage and then started to codecollcell. Ironically,tikz-timingnow simply removes\ignorespacesand uses\unskipor\\as end-marker, so it doesn't needcollcell:-) – Martin Scharrer Mar 04 '11 at 10:37collcell. 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\noalignin atabularxenvironment (that may not be the exact issue, I stopped debugging because collcell just works). – Gilles 'SO- stop being evil' Dec 27 '13 at 18:47