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.
morbusg
, not morsburg
.
:-)
) Can't you just do this in collcell
somehow? @morbusg: +1, nicely written up answer!
Mar 6, 2011 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}
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
:-)
Mar 4, 2011 at 10:37
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).
Dec 27, 2013 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 !
.
\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.
Mar 4, 2011 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
).
\multicolumn
.
Mar 28, 2011 at 11:15
\begin{tabular}{\arg{\mymacro}c} a&b\\ \multicolumn{2}{|c|}{cde} \\ \end{tabular}
?
Mar 28, 2011 at 15:29
\arg
in the second argument of \multicolumn
doesn't work.
Mar 28, 2011 at 15:34
\span
and adding some \iffalse{\fi... \iffalse}\fi
.
Mar 28, 2011 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.
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}