12

Is there a way to determine the width of the first column in a tabular enviroment?

I've thought about using a savebox but that would only give me the size of the text (and in one cell only), not the actual column width.

Or should I use longtable (or another package) to do that?

LaRiFaRi
  • 43,807
masu
  • 6,571

2 Answers2

13
\documentclass{article}
\usepackage{array}

\makeatletter
\protected\def\z#1{\pdfsavepos\write\@auxout{\gdef\string\tpos#1{\the\pdflastxpos}}}%
\def\foo#1#2{\ifcsname tpos#1\endcsname\the\dimexpr\csname tpos#2\endcsname sp -\dimexpr\csname tpos#1\endcsname sp\relax\fi}
\makeatother

\begin{document}

\begin{tabular}{!{\z{a}}l!{\z{b}}c!{\z{c}}r!{\z{d}}}
abc & def & ghi \\
ABC & \multicolumn{2}{c}{aaa} \\
1 & 12 & 123
\end{tabular}

The width of the first column was \foo{a}{b}

The width of the second column was \foo{b}{c}

The width of the third column was \foo{c}{d}

\end{document}

enter image description here

Slightly different result than egreg, as the code takes a different view of whether tabcolsep padding is included or not.

David Carlisle
  • 757,742
  • +1, great, but egreg's answer is a little more generic (You have to actually print to table to use this, so it can't effect the the actual table. Or am I mistaken?) – masu Jan 07 '14 at 13:49
  • 1
    @SándorKazi You can use the lengths within the table, latex will sort itself out on the next run. – David Carlisle Jan 07 '14 at 14:03
12

This has some limitations on the tabular: you can't have \multicolumn in the last row, nor optional arguments to \\ (this one may be lifted off).

\documentclass{article}
\usepackage{environ}

\makeatletter
\NewEnviron{mtabular}[3][c]{%
  \begingroup
  \renewcommand{\multicolumn}[3]{\multispan{##1}##3}%
  \let\\\cr
  \setbox\tw@=\vbox{%
    \ialign{&##\unskip\hfil\cr\BODY\crcr}%
    \get@widths{#3}%
  }%
  \endgroup
  \begin{tabular}[#1]{#2}\BODY\end{tabular}}

\def\get@widths#1{%
  \def\@temp{\else\@latex@warning{No such column}\fi}
  \setbox\z@=\lastbox
  \get@next@width
  \xdef#1##1{%
    \noexpand\ifcase##1\relax\unexpanded\expandafter{\@temp}%
  }%
}
\def\get@next@width{%
  \setbox\z@=\hbox{\unhbox\z@\unskip\global\setbox\@ne=\lastbox}%
  \ifvoid\@ne
  \else
    \edef\@temp{\noexpand\or\the\wd\@ne\unexpanded\expandafter{\@temp}}%
    \expandafter\get@next@width
  \fi
}
\makeatother

\begin{document}

\begin{mtabular}{lcr}{\foo}
abc & def & ghi \\
ABC & \multicolumn{2}{c}{aaa} \\
1 & 12 & 123
\end{mtabular}

The width of the first column was \foo{1}

The width of the second column was \foo{2}

The width of the third column was \foo{3}

\end{document}

It works by first typesetting the table in a “reduced” form, then taking off its last row and dismantling it bit by bit. The last argument to mtabular is a macro name that can later be used with a numeric argument for getting the relative column width.

enter image description here

egreg
  • 1,121,712
  • +1 and accepted, thanks. But shouldn't there be % at the end of the line before \endgroup. I think this might cause some unwanted spacing. – masu Jan 07 '14 at 13:51
  • @SándorKazi Yes, there should be. Still, an use example would be better, to clarify your aims. – egreg Jan 07 '14 at 13:52
  • I was just curious if it was possible. Here's what made me curious: http://tex.stackexchange.com/q/152784/36821 I've constructed an answer for this question based on your solution for this one. – masu Jan 07 '14 at 15:30
  • Will this also work for longtable? – Niranjan Sep 25 '19 at 02:28
  • @Niranjan No: longtable doesn't build all the table in one swoop and uses multiple runs of LaTeX to stabilize the column widths. – egreg Sep 25 '19 at 09:20