The code below defines a vtab
environment which reads its body (thanks to the environ
package) and splits it into columns, and cells (using some LaTeX3 code), then puts it back together in rows rather than columns, and places its two arguments before and after the result. It is used as
\begin{vtab}{\begin{tabular}{cccc}}{\end{tabular}}
a\\b\\c\\d&
e\\f&
g\\h\\i&
j\\k\\l\\m\\n\\o
\end{vtab}
There are some comments in the code below, don't hesitate to ask. Earlier, I forgot the \ExplSyntaxOff
line, which restores the normal TeX behaviour (spaces not ignored).
\RequirePackage{expl3}
\RequirePackage{environ}
\ExplSyntaxOn
% \NewEnviron defines |\begin{vtab}| to grab until |\end{vtab}|
% and store the result in |\BODY|. Then two steps.
% (1) Split |\BODY| into cells, storing them in a property list.
% (2) Read the property list in a different order, building the
% body of the tabular as we go.
% (3) Typesetting the tabular.
%
\NewEnviron { vtab } [2]
{
\TV_read:V \BODY
\TV_build:
\tl_put_left:Nn \l_TV_result_tl { #1 }
\tl_put_right:Nn \l_TV_result_tl { #2 }
\tl_use:N \l_TV_result_tl
}
% We need some variables.
\int_new:N \l_TV_col_int
\int_new:N \l_TV_row_int
\int_new:N \l_TV_max_row_int
\prop_new:N \l_TV_cells_prop
\tl_new:N \l_TV_result_tl
\tl_new:N \l_TV_row_tl
\tl_new:N \l_TV_cell_tl
% Generic function to split a list with items delimited by a given token
% (in our application, either & or \\) and apply the third argument to
% each item that was found: this third argument will receive the item as
% |#1|. Used as |\TV_map_inline:nnn {\\} {a\\b\\c} {do #1}|.
%
% It is slightly tricky to get nesting to work (see e.g., explanations
% for |\clist_map_inline:nn| in |l3clist.dtx|).
%
\int_new:N \g_TV_map_inline_int
\cs_new_protected:Npn \TV_map_inline:nnn #1 #2 #3
{
\tl_if_empty:nF {#2}
{
\cs_gset_eq:cN
{TV_map_inline_\int_use:N \g_TV_map_inline_int :w}
\TV_map_inline_aux:w
\int_gincr:N \g_TV_map_inline_int
%
\cs_gset:Npn \TV_map_inline_aux:w ##1 #1
{
\quark_if_recursion_tail_stop:n {##1}
#3
\TV_map_inline_aux:w
}
\TV_map_inline_aux:w #2 #1 \q_recursion_tail #1 \q_recursion_stop
%
\int_decr:N \g_TV_map_inline_int
\cs_gset_eq:Nc
\TV_map_inline_aux:w
{TV_map_inline_\int_use:N \g_TV_map_inline_int :w}
}
}
% We split into columns first |&|, then rows |\\|. While doing this,
% we keep track of the index of the row and column, and what the
% highest row number is (this will be the number of rows in the
% resulting tabular). The cell's content is stored as the property
% "row,column" in |\l_TV_cells_prop|.
%
\cs_new:Npn \TV_read:n #1
{
\int_zero:N \l_TV_col_int
\int_zero:N \l_TV_max_row_int
\TV_map_inline:nnn {&} {#1}
{
\int_incr:N \l_TV_col_int
\int_zero:N \l_TV_row_int
\TV_map_inline:nnn {\\} {##1}
{
\int_incr:N \l_TV_row_int
\exp_args:NNx \prop_put:Nnn \l_TV_cells_prop
{ \int_use:N \l_TV_row_int , \int_use:N \l_TV_col_int }
{ ####1 }
}
\int_compare:nT { \l_TV_row_int > \l_TV_max_row_int }
{ \int_set_eq:NN \l_TV_max_row_int \l_TV_row_int }
}
}
\cs_generate_variant:Nn \TV_read:n {V}
% To build, loop for |##1| from 1 to the number of rows,
% and for |####1| from 1 to the number of columns, and extract
% the relevant cell, then place it in the relevant row.
% The funny |\use_none:n| business removes the first |&| from
% each row as it is added to the result.
\cs_new:Npn \TV_build:
{
\tl_clear:N \l_TV_result_tl
\prg_stepwise_inline:nnnn {1} {1} { \l_TV_max_row_int }
{
\tl_clear:N \l_TV_row_tl
\prg_stepwise_inline:nnnn {1} {1} { \l_TV_col_int }
{
\prop_pop:NnNF \l_TV_cells_prop { ##1 , ####1 } \l_TV_cell_tl
{ \tl_clear:N \l_TV_cell_tl }
\tl_put_right:Nx \l_TV_row_tl { & \exp_not:V \l_TV_cell_tl }
}
\exp_args:NNf \tl_put_right:Nn \l_TV_result_tl
{ \exp_after:wN \use_none:n \l_TV_row_tl \\ }
}
}
\ExplSyntaxOff % [EDIT: added that line]
\documentclass{article}
\begin{document}
\begin{vtab}{\begin{tabular}{cccc}}{\end{tabular}}
a\\b\\c\\d&
e\\f&
g\\h\\i&
j\\k\\l\\m\\n\\o
\end{vtab}
\end{document}
tabular
environment uses the plainTeX\halign
primitive internally which needs the row-by-row format. This can't be changed. One funny idea would be to turn every cell 90degrees and then the whole table 90degr backwards, making effectively rows to columns and vice versa. However, then the cell alignment (c
,l
,r
, ..) would not work as usual of course.\valign
but you can't just say{\let\halign\valign\begin{tabular}{..} ..
, can you?