How to know the number of columns declared in a tabular environment?

you can count the & in the generated \halign preamble

enter image description here

\documentclass{article}
\usepackage{array,xparse}

\NewDocumentEnvironment{TikzTable}{md<>O{c}m}{%
\IfNoValueTF{#2}{%
    \begin{#1}[#3]{#4}}{%
    \begin{#1}{#2}[#3]{#4}}
}{\end{#1}}

\makeatletter
\def\zzz#1#2&#3{%
\ifx\zzz#3#1\expandafter\@gobble\else
\expandafter\@firstofone
\fi
{\zzz{\the\numexpr#1+1\relax}#3}}

\def\zz{\noalign{%
\xdef\nocols{\expandafter\zzz\expandafter1\@preamble&\zzz}%
}}
\makeatother

\begin{document}
\begin{TikzTable}{tabular}[b]{clrm{3cm}}
\zz
\hline
a&b&c& \nocols\ columns \\% At this point
\hline
1&1&1&1\\
\end{TikzTable}bob

\end{document}

Using the same idea as David, but with fancier expl3 code; this makes \nocols available in every TikzTable environment, but the name is customizable in a trailing optional argument in case you need to nest those tables.

\documentclass{article}
\usepackage{array,xparse}

\NewDocumentEnvironment{TikzTable}{md<>O{c}mO{\nocols}}
 {%
  \IfNoValueTF{#2}
   {%
     \begin{#1}[#3]{#4}
   }{%
     \begin{#1}{#2}[#3]{#4}
   }%
  \noalign{\CountColumns{#5}}
 }
 {\end{#1}}

\ExplSyntaxOn
\NewDocumentCommand{\CountColumns}{m}
 {% count the number of & tokens in \@preamble
  \regex_count:nvN { \cT\& } { @preamble } \l_tmpa_int
  % they're one less than the columns
  \cs_gset:Npx #1 { \int_eval:n { 1 + \l_tmpa_int } }
 }
\cs_generate_variant:Nn \regex_count:nnN { nv }
\ExplSyntaxOff

\begin{document}

\begin{TikzTable}{tabular}[b]{clrm{3cm}}
\hline
a&b&c& This table has \nocols\ columns \\
\hline
1&1&1&1\\
\end{TikzTable}bob

\begin{TikzTable}{tabular}[b]{clrm{3cm}}[\foo]
\hline
a&b&c& This table has \foo\ columns \\
\hline
1&1&1&1\\
\end{TikzTable}bob

\end{document}

enter image description here


Here's a LuaLaTeX-based solution. It can handle tabular, array, tabular*, tabularx, and tabulary environments, as well as the TikzTable environment you proposed in your posting.

The number of declared columns of the most recently encountered tabular-like environment is stored in a Lua variable called num_cols. (Note that it's not necessary to do anything manually to obtain the number of declared columns for each tabular-like environment -- the calculations are done fully automatically.) To access this number from the LaTeX side, the code provides a LaTeX macro named \numcols.

The only input requirement is that the \begin{tabular}...{<columnspec>} material all has to be on one and the same line.

Note that the code is designed to handle cases such as \begin{tabular} {@{} c >{$}c<{$} >{\raggedleft\arraybackslash\tt}p{1cm} @{}} \\ The column count will be "3". The solution method can also handle more-complicated column definitions, such as *{6}{l}.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
%% next few lines from the OP's query
\usepackage{array,xparse}
\NewDocumentEnvironment{TikzTable}{md<>O{c}m}{%
\IfNoValueTF{#2}{%
    \begin{#1}[#3]{#4}}{%
    \begin{#1}{#2}[#3]{#4}}}{%
    \end{#1}}
\usepackage{tabularx,tabulary}

\usepackage{luacode} % for 'luacode' environment
\begin{luacode}
-- Define a global variable (num_cols), set up two 
-- Lua functions, and assign one of them to the    
-- 'process_input_buffer' callback.

-- Initialize counter variable
num_cols = 0 

-- The next function computes the number of columns from
-- contents of string 'zz'
function calc_nums ( zz ) 
    -- retain the first "{....}" substring
    zz = zz:gsub ( "^.-(%b{}).-$", "%1" )
    -- remove outermost pair of curly braces
    zz = zz:sub  ( 2 , -2 )    
    -- expand expressions such as "*{5}{l}" to "lllll"
    zz = zz:gsub ( "%*%s-{(%d-)}%s-(%b{})" , 
                      function ( y , z )
                         z = z:sub ( 2 , -2 )
                         return string.rep ( z , y ) 
                      end )
    -- omit all stuff in curly braces
    zz = zz:gsub ( "%b{}" , "" ) 
    -- some more characters to ignore
    zz = zz:gsub ( "[@!|><%s%*]" , "" ) 
    -- Number of remaining chars in "zz" is the number
    -- of columns in the tabular-like environment.
    num_cols = string.len ( zz ) 
end

-- Next the main Lua function. Scan all input lines. 
-- If we detect start of a tabular-like env., lop off 
-- the prefix and pass the remainder of the input line 
-- to the 'calc_nums' function to determine number of cols.
-- ("%s-" means "0 or more instances of whitespace")
function get_col_spec ( s )
  local zz
  if string.find ( s , "\\begin.-{tabular}" ) then
     zz = s:gsub ( "^.-\\begin.-{tabular}" , "" )
     calc_nums ( zz )
  elseif string.find ( s , "\\begin%s-{array}" ) then
     zz = s:gsub ( "^.-\\begin%s-{array}" , "" )
     calc_nums ( zz )
  elseif string.find ( s , "\\begin%s-{tabular.}" ) then
     zz = s:gsub ( "^.-\\begin%s-{tabular.}%s-%b{}" , "" )
     calc_nums ( zz )
  end
  -- Do nothing if no match occurred.
end

-- Finally, assign 'get_col_spec' to the LuaTeX
-- 'process_input_buffer' callback.
luatexbase.add_to_callback( "process_input_buffer", 
    get_col_spec, "get_cols" )
\end{luacode}
%% LaTeX-side code: a macro to print out the number of columns
\newcommand\numcols{\directlua{tex.sprint(num_cols)}}

\begin{document}

%% Example 1
   \begin{tabular} [b] { | * {6} { m{4mm }|} p { 12mm }|} \multicolumn{3}{@{}l}{\numcols\ columns} 
   \\ \hline a & b & c & d & e & f & g \\ \hline
   \end{tabular}

\bigskip
%% Example 2
\begin{tabular} {@{} c *{2}{>{$}c<{$}} >{\raggedleft\arraybackslash\tt}p{3cm} @{}} 
\hline
a & b & c & \numcols\ columns\\ 
\hline
\end{tabular}

\bigskip
%% Example 3: the 'TikzTable' case
aaa\begin{TikzTable}{tabular}[b]{@{}cllrm{1.55cm}@{}}\hline
a&b&c&d& \numcols\ columns \\
\hline
1&1&1&1&1\\
\hline
\end{TikzTable}zzz

\bigskip
%% Examples 4 to 6: array, tabular*, and tabularx
$\begin{array}{@{}*{6}{c}@{}} \hline a & b & c & d & e & \numcols \\ \hline \end{array}$

\bigskip
\begin{tabular*}{0.5\textwidth}{@{\extracolsep{\fill}}*{7}{l}@{}} \hline
z & y & x & w & v & u & \numcols\\ \hline
\end{tabular*}

\bigskip
\begin{tabularx}{0.7\textwidth}{@{}l*{8}{>{\centering\arraybackslash}X}r@{}} \hline
z & y & x & w & v & u & t & s & r & \numcols\\ \hline
\end{tabularx}

\end{document}

Tags:

Tables