Here's a quickly hacked-up solution. As noted by @DavidCarlisle, the \widesplit
command from this answer is probably a better solution.
\documentclass[draft,runnngheads]{book}
\usepackage{mptab}
\begin{document}
\mptab{\the\columnsep}{\textwidth}{
{$a_1$, $a_2$, $a_3$, $b_1$, $b_2$, $c_1$, $c_2$, $c_3$, $d_1$, $d_2$, $i_1$, $i_2$, $e_1$, $e_2$, $h_1$, $h_2$, test, test22, test33, test 4, test 5, test 6, test 7, test 8, test 9},
{$x_1$, $x_2$, $x_3$, $y_1$, $y_2$, $z_1$, $z_2$, $z_3$, $t_1$, $t_2$, $w_1$, $w_2$, $f_1$, $f_2$, $g_1$, $g_2$, hello, world, bye, bye, lots, of, data, beep, boop},
{$x_1$, $x_2$, $x_3$, $y_1$, $y_2$, $z_1$, $z_2$, $z_3$, $t_1$, $t_2$, $w_1$, $w_2$, $f_1$, $f_2$, $g_1$, $g_2$, hello, world, bye, bye, lots, of, data, beep, boop},
{1, 2, 3, a rather very long cell, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
}
\end{document}
Which gives the following 3-pages PDF:
And here's mptab.sty
:
It likely contains a nutritive amount of bugs and needless complexity, uses a comma instead of &
and braces instead of \\
. It does not support \hline
, and I haven't made it so that you can specify the format (e.g. vertical lines with |
are not possible). All these should be rather simple to add to the code, and I've included some amount of comments. The only hard thing for me would be to make it accept the &
and \\
syntax, as I'm not familiar with hooking up into such low-level catcode-ridden features of TeX. It also uses up a \newlength
when it probably could get away with using \bgroup…\egroup
and an existing temporary dimension, and it overuses \global in a lot of places.
But it works, for simple cases at least.
Any improvement is welcome, and this dirty code is in the public domain (CC0, WTFPL, you choose). I'll try to add an alternative to \hline
, format specification, and the possibility to mix chunks of the table and text, if I find the time (no promises!).
\usepackage{tikz}
\newlength{\mylen}
%
\newif\iffirstcolumn%
\newif\iffirstline%
\xdef\i{0}% Initialize column counter before first iteration.
\def\mptab#1#2#3{%
\bgroup%
\setlength\columnsep{#1}%
% row counter:
\xdef\j{0}%
% Loop over lines:
\global\firstlinetrue%
\foreach \y in {#3}{%
% Increment row counter
\xdef\oldj{\j}%
\pgfmathtruncatemacro{\j}{\j+1}%
\xdef\j{\j}%
% Column counter:
\xdef\oldi{\i}%
\xdef\i{0}%
\foreach \x in \y{%
% Increment column counter:
\pgfmathtruncatemacro{\i}{\i+1}%
\xdef\i{\i}%
% Compute width of current column
\settowidth{\mylen}{\x}%
\iffirstline%
\expandafter\xdef\csname column\i maxwidth\endcsname{\the\mylen}%
\else%
% Make an alias for the currently computed column max width, for convenient access:
\expandafter\let\expandafter\currentcolumnmaxwidth\csname column\i maxwidth\endcsname%
% Compare this cell's width:
\ifdim\mylen>\currentcolumnmaxwidth\relax%
% And update the column's max width when the current cell is wider:
\expandafter\xdef\csname column\i maxwidth\endcsname{\the\mylen}%
\fi%
\fi%
% Remember the contents of this cell:
\global\expandafter\let\csname cell\i x\j\endcsname\x%
}%
\global\firstlinefalse%
}
%
% Remember last column number:
% For some reason, the foreach loop from tikz gives the line with an extra
% pair of braces (which breaks the inner loop, as it sees only one value)
% when there's no trailing comma after the last line, but gives an empty
% line when there is a trailing comma. We detect this idiosyncrasy here and
% revert the last column number and last line:
\ifnum\i=0\relax%
\xdef\lastcolumn{\oldi}%
\xdef\lastline{\oldj}%
\else%
% We still keep the "reasonnable" behaviour here, just in case.
\xdef\lastcolumn{\i}%
\xdef\lastline{\j}%
\fi%
% \message{Last line: \lastline, Last column: \lastcolumn}%
%
%
% Initialization for the loop which aggregates all cells per page:
\expandafter\xdef\csname tablepage1\endcsname{}%
\expandafter\xdef\csname tableformat1\endcsname{}%
\global\firstlinetrue%
% Counter for the last page:
\xdef\maxtablepage{1}%
%
% Loop over lines, aggregating each cell in its page.
\foreach \y in {1,...,\lastline}{%
\global\setlength{\mylen}{0pt}%
\xdef\curtablepage{1}
\global\firstcolumntrue%
% Loop over the columns, aggregating each cell in its page.
\foreach \x in {1,...,\lastcolumn}{%
\global\addtolength{\mylen}{\columnsep}%
\global\addtolength{\mylen}{\csname column\x maxwidth\endcsname}%
\global\addtolength{\mylen}{\columnsep}%
\ifdim\mylen>#2\relax%
% Push to next page
% Reset loop variables:
\global\setlength{\mylen}{0pt}%
% Re-add current cell width:
\global\addtolength{\mylen}{\columnsep}%
\global\addtolength{\mylen}{\csname column\x maxwidth\endcsname}%
\global\addtolength{\mylen}{\columnsep}%
% Bump table page number:
\pgfmathtruncatemacro{\curtablepage}{\curtablepage+1}%
\xdef\curtablepage{\curtablepage}
% Initialize new empty page and format:
\iffirstline
\expandafter\xdef\csname tablepage\curtablepage\endcsname{}%
\expandafter\xdef\csname tableformat\curtablepage\endcsname{}%
% Bump the counter for the last page
\xdef\maxtablepage{\curtablepage}%
\fi
% We're back on the first column:
\global\firstcolumntrue%
\fi%
% Still fits on this page (or we just created a brand new page):
% Create convenient aliases for the current page, format and cell:
\expandafter\let\expandafter\thiscell\csname cell\x x\y\endcsname%
\expandafter\let\expandafter\thistablepage\csname tablepage\curtablepage\endcsname%
\expandafter\let\expandafter\thistableformat\csname tableformat\curtablepage\endcsname%
% If we're on the first line, add a new column to the format
\g@addto@macro\thistableformat{@{\hspace{\the\columnsep}}l@{\hspace{\the\columnsep}}}% THE COLUMN FORMAT HERE
% Write back to \csname tableformat\curtablepage\endcsname:
\global\expandafter\let\csname tableformat\curtablepage\endcsname\thistableformat%
%
% The \expandafter and \noexpand tricks
% are from https://tex.stackexchange.com/a/60976/5699
% and from https://tex.stackexchange.com/a/67368/5699
\iffirstcolumn%
\global\firstcolumnfalse%
\edef\doit{%
\noexpand\g@addto@macro\noexpand\thistablepage{%
% \noexpand\hspace{\noexpand\columnsep}%
\expandafter\noexpand\thiscell%
% \noexpand\hspace{\noexpand\columnsep}%
}%
}%
\else%
\edef\doit{%
\noexpand\g@addto@macro\noexpand\thistablepage{%
% \noexpand\hspace{\noexpand\columnsep}%
& \expandafter\noexpand\thiscell%
% \noexpand\hspace{\noexpand\columnsep}%
}%
}%
\fi%
\doit%
% Write back to \csname tablepage\curtablepage\endcsname:
\global\expandafter\let\csname tablepage\curtablepage\endcsname\thistablepage%
}%
%Add a \\ at the end of the line on each page:
\foreach \curtablepage in {1,...,\maxtablepage}{%
% Make an alias
\expandafter\let\expandafter\thistablepage\csname tablepage\curtablepage\endcsname%
% Add the "\\"
\edef\doit{%
\noexpand\g@addto@macro\noexpand\thistablepage{%
\noexpand\\%
}%
}%
\doit%
% Write back to \csname tablepage\curtablepage\endcsname:
\global\expandafter\let\csname tablepage\curtablepage\endcsname\thistablepage%
}
%Finished handling the line:
\global\firstlinefalse
}%
%
%
\foreach \i in {1,...,\curtablepage}{%
\noindent\begin{tabular}{\csname tableformat\i\endcsname|}%
\csname tablepage\i\endcsname%
\end{tabular}%
\clearpage%
}%
%
\egroup%
}%
siunitx
package for format columns with numbers in a easy way. Thelongtable
package is useful when you need to create a table across two or more pages.minipage
nor the\somecolumns
trick appeal, then I think you need to consider a format other than LaTeX and maybe re-engineering TeX's output routine. So good luck with that ;). You are asking for something which cannot be done automatically and elegantly in current LaTeX. You either change your desiderata or you have to accept one of the ingenious hacks put forward. Boxes, coffins, hidden columns, rotate the table, use landscape, one of David's tricks ....