2

I'd like to define a command called \headers that takes an undefined number of parameters.

e.g. \headers{Category One}{Category Two}{Category Three}

And it would output the following:

\textbf{\textit{Category One}} & 
\textbf{\textit{Category Two}} &
\textbf{\textit{Category Three}} \\
\hline
\hline

The idea is to use this inside a custom tabularx package I've used, so I could just go:

\begin{tabularx}{\hsize}{XXX}
    \headers{Category One}{Category Two}{Category Three}
\end{tabularx}

How could I achieve something like this? I saw a lot about xparse and \clist_map_inline:nn but none of that would allow the & character to join any parameter after the first.

Any help would be deeply appreciated.

7
  • 1
    Welcome to TeX.SE! – Mico Dec 21 '19 at 19:31
  • 2
    Would a LuaLaTeX-based solution be acceptable, or are you restricted to using pdfLaTeX? – Mico Dec 21 '19 at 19:32
  • You can highlight code in your post using back-ticks. To highlight code-blocks, either indent them by four spaces or use the {} on the gui. – user30471 Dec 21 '19 at 20:06
  • @Andrew Weird. I did use the back-ticks, but maybe I did something wrong. I'll use the {} next time! Thank you! – Extremo Dec 21 '19 at 20:56
  • @Mico I am afraid I dont know the difference of the two. I do need to export to PDF at the end. – Extremo Dec 21 '19 at 20:57
2

You can get output like:

enter image description here

with the code:

\documentclass{article}
\usepackage{tabularx}
\usepackage{etoolbox}
\usepackage{booktabs}
  \makeatletter
\newcommand\headers[1]{%
  \def\sep{}%
  \def\realheader{}%
  \renewcommand*\do[1]{\protected@xappto\realheader{\sep\textbf{\textit{##1}}}\xdef\sep{&}}
  \docsvlist{#1}%
  \\\toprule\realheader\\\midrule
}
\makeatother

\begin{document}

\begin{tabularx}{\hsize}{XXX}
  \headers{Category one, Category two, Category three}
  stuff & stuff & stuff\\
  \bottomrule
\end{tabularx}

\end{document}

Rather than using \hline I have succumbed to my biases and used the booktabs package as I think this gives much better output.

Apart from using booktabs the main change from the OP is that I have changed the syntax to use a command separated list for the header, which is then turned into the table header using \docsvlist from the etoolbox package. Unfortunately, this seems to require a little bit of expansion trickery using \protected@xappto to construct the header piece by piece.

EDIT

Here is a fancier version that defines a new table environment mytable that takes one argument that specifies the column headers as a comma separated list, and where body of the environment contains the (tabularx) environment. Using this the code:

\begin{mytable}{Category one, Category two, Category three}
  stuff & stuff & stuff\\
\end{mytable}

produces

enter image description here

which is essentially the same as above except that I have used the OPs formatting. The main advantage of this approach is that you do not have the specify the column headers so that, for example,

\begin{mytable}{Category one, Category two, Category three, Column four}
  stuff & stuff & stuff & stuff\\
\end{mytable}

works as expected.

Here is the modified code (see the comments for an explanation of what the code is doing):

\documentclass{article}
\usepackage{tabularx}
\usepackage{etoolbox}
\makeatletter
\newcounter{mytablecolumns}% to automate the number of columns
\newenvironment{mytable}[1]{%
  \def\sep{}% will be the table column separator
  \setcounter{mytablecolumns}{0}% reset column counter
  \def\realheader{}% will become the table header
  \renewcommand*\do[1]{% construct each entry in the header
    \protected@xappto\realheader{\sep\textbf{\textit{##1}}}% add header
    \stepcounter{mytablecolumns}% increment column counter
    \xdef\sep{&}% set up next column separator
  }
  \docsvlist{#1}% create the table header
  \xdef\sep{*{\arabic{mytablecolumns}}X}% create the table specifications
  \expandafter\tabularx\expandafter\hsize\expandafter{\sep}% start tabularx
  \realheader\\\hline\hline% insert header and two \hlines
  }{\endtabularx}% end tabularx environment
\makeatother

\begin{document}

\begin{mytable}{Category one, Category two, Category three}
  stuff & stuff & stuff\\
\end{mytable}

\end{document}
3
  • I couldn't get this to work in my custom tabularx. Could you explain what you're actually doing there? Maybe I can then replicate something similiar. – Extremo Dec 21 '19 at 21:16
  • I got it to work using the following ` \newcommand{\headers}[1] { \renewcommand*\do[1]{\textbf{\textit{##1}} &} \docsvlist{##1} \hline \hline } ` Thanks for your help and finding the package! – Extremo Dec 21 '19 at 21:35
  • @Extremo See my edit for a fancier version – user30471 Dec 21 '19 at 22:49
2

Here's a LuaLaTeX-based solution. Note that it loads the booktabs package and employs \midrule instead of \hline\hline.

All of the actual work is performed by the Lua function called headers, which employs Lua's powerful string.gsub function. The headers function is assigned to LuaTeX's process_input_buffer callback, which operates at very early stage, before TeX starts its usual macro expansion work.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{tabularx,booktabs}
\usepackage{luacode}
\begin{luacode}
-- start of Lua code
function headers ( s )
  if string.find ( s , "^%s-\\headers" ) then
    s = s:gsub ( "%b{}" , "&\\textbf{\\textit%0}" )
    s = s:gsub ( "\\headers&" , "" ) .. "\\\\ \\midrule"
  end
  return s
end
-- end of Lua code
\end{luacode}
%% assign 'headers' function to LuaTeX's 'process_input_buffer' callback
\AtBeginDocument{\directlua{luatexbase.add_to_callback(
  "process_input_buffer",headers,"headers")}}

\begin{document}
\noindent
\begin{tabularx}{\textwidth}{XXX}
  \toprule
  \headers{Category One}{Category Two}{Category Three} 
\end{tabularx}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.