10

Is it possible to create a \newcolumntype-like macro accepting more than one argument and one of them is an optional argument?


I want to create a column type A that can accept more than 1 argument such that I can create a tabular as follows:

\begin{tabular}{|A[2cm]{1cm}{5cm}|c|l|r|}
...
\end{tabular}

Note: the column type A accepts 3 arguments in this example.

  • Perhaps a bit more detail on what is wanted might be useful! I'm not sure if it is the macro \newcolumntype itself or the resulting letter that you want to alter. – Joseph Wright Dec 30 '10 at 18:51
  • @Joseph, please see my new edit. – xport Dec 30 '10 at 19:00
11

Herbert has explained how to do mandatory arguments. Optional arguments is doable but requires some low-level hackery, auxiliary functions and is not for the faint-hearted. You can see two versions of the same approach in numprint and siunitx (the later is an adaptation of the former).

\makeatletter
\newtoks\mytoks
\mytoks\expandafter{\the\NC@list}
\newcolumntype{A}{}
\NC@list\expandafter{\the\mytoks \NC@do A}
\renewcommand*{\NC@rewrite@A}[3][]{%
  \@temptokena\expandafter{%
    \the\@temptokena 
      % INSERT DEFINITION HERE!
  }%
  \NC@find
}
\makeatother
  • Is there a reason for using \csname NC@rewrite@A\endcsname (and the \expandafters) rather than \NC@rewrite@A? – cgnieder Jan 26 '13 at 21:28
  • @cgnieder Not here, but there is where I've copied it from! I'll edit. – Joseph Wright Jan 26 '13 at 21:59
8

not with an optional argument, only with mandatory ones:

\documentclass{article}
\usepackage{array} 

\newcolumntype{A}[3]{@{\vrule\kern#1\vrule}p{#2}@{\vrule\kern#3\vrule}}
\begin{document} 

\begin{tabular}{|A{2cm}{1cm}{5cm}|c|l|r|}
foo & bar & baz & foobar
\end{tabular}

\end{document}
  • first of all thanks. However, if I define an optional argument as follow \newcolumntype{A}[3][1cm] and \begin{tabular}{|A[2cm]{1cm}{5cm}|c|l|r|}, I got compilation errors. – xport Dec 30 '10 at 19:12
  • 4
    I wrote "not" with an optional argument! – user2478 Dec 30 '10 at 19:18
0

starting off with Joseph Wright's answer I have developed a hack which allows to define new column types with an optional parameter with the \newcolumntype command:

\documentclass{article}
\usepackage{array}
\usepackage{booktabs}

% ---------- hack to allow optional parameters with \newcolumntype ----------
\makeatletter
% newcommand with default value for optional parameter but without test whether command exists
% because array package has a different policy: warning instead of error if column type is already defined
\def\@xargdef@withoutcheck#1[#2][#3]#4{%
    % copied from \show\@xargdef without \@ifdefinable
    % also see The LaTeX 2e Sources (2014/05/01 p24f)
    \expandafter \def \expandafter #1\expandafter {%
        \expandafter \@protected@testopt \expandafter #1\csname \string #1\endcsname {#3}%
    }%
    \expandafter \@yargdef \csname \string #1\endcsname \tw@ {#2}{#4}%
}

% save a backup of original command which I am going to override
\let\original@newcol@\newcol@

% redefine a command which is internally called by \newcolumntype.
% check whether column type is already existing has already been done
% and existence of first optional argument (number of parameters) has been confirmed,
% see array package documentation (November 3, 2014 p21f).
% check whether 2nd optional argument is given:
\def\newcol@#1[#2]{%
    \@ifnextchar[%
        {\my@newcol@#1[#2]}%
        {\original@newcol@#1[#2]}%
}

% custom command which handles 2nd optional argument (default value of optional parameter)
\def\my@newcol@#1[#2][#3]#4{\expandafter\@xargdef@withoutcheck\csname NC@rewrite@#1\endcsname[#2][#3]{\NC@find#4}}
\makeatother


% ---------- example usage ----------
\newcolumntype{m}[1][c]{>{$} #1 <{$}}
\newcolumntype{M}[1][c]{>{\displaystyle}m[#1]}

\newcolumntype{A}[3][0em]{>{\typeout{opt: #1}\rule[#1]{#2}{#3}} l <{\rule[#1]{#2}{#3}}}


% ---------- test document ----------
\begin{document}
\begin{center}
\begin{tabular}{M[l] M M[r]}
    \toprule
    a+b=c & a+b=c & a+b=c \\
    1 & 2 & 3 \\
    \bottomrule
\end{tabular}
\end{center}
\bigskip

Please note that in this case it is necessary to add curley braces around the optional argument because otherwise the `m' of the unit would be interpreted as a column specifier:
\begin{center}
\begin{tabular}{A{1em}{.5pt} A[{.3em}]{1em}{.5pt}}
    \toprule
    1 & a\\ 
    2 & b\\
    3 & c\\
    hello & world \\
    \bottomrule
\end{tabular}
\end{center}
\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.