5

I have the following code with a command that creates rows for a tabular:

\documentclass[letterpaper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{xstring}

\newcommand*{\condrow}[2]{
\IfEqCase{#1}{
 {l}{#2 & & \\}
 {r}{ & & #2 \\}
 {c}{ & #2 & \\}
 {m}{\multicolumn{3}{c}{#2} \\}
}[\PackageError{condrow}{Undefined option: #1}{}]
}

\begin{document}
\begin{tabular}{|c|c|c|}
 \condrow{l}{left}
 \condrow{r}{right}
 \condrow{c}{center}
 \multicolumn{3}{c}{manual multi} \\ % WORKS
 \condrow{m}{condrow multi} % FAILS
\end{tabular}
\end{document}

While using the \multicolumn directly in the tabular works, using \multicolumn through the command \condrow fails. My guess is that \IfEqCase in \condrow prepends something to the beginning of the \multicolumn command, triggering the following error:

! Misplaced \omit.
\multispan ->\omit 
                   \@multispan 
l.20  \condrow{m}{condrow multi}
                                 % FAILS

Prepending \\ before \multicolumn in the command makes the error disappear, but inserts an empty row. The problem Misplaced \omit. \multispan with \newcommand is similar. However, the answers do not solve my case. I have tried using the ifthen package for branching without success.

Any ideas how to fix this?

faf0
  • 53

4 Answers4

6

As Werner said you need an expandable test. As you are just comparing single letters an alternative to \pdfstrcmp is \if

\documentclass[letterpaper,10pt]{article}

\newcommand*{\condrow}[2]{%
       \if l#1 #2 & & \\%
  \else\if r#1 &  & #2 \\%
  \else\if c#1 & #2 & \\%
  \else\if m#1\multicolumn{3}{c}{#2} \\%
  \else\PackageError{condrow}{Undefined option: #1}{}%
  \fi\fi\fi\fi%
}


\begin{document}
\begin{tabular}{|c|c|c|}
  \condrow{l}{left}
  \condrow{r}{right}
  \condrow{c}{center}
  \multicolumn{3}{c}{manual multi} \\ % WORKS
  \condrow{m}{condrow multi} % WORKS
\end{tabular}
\end{document}
David Carlisle
  • 757,742
4

This is exactly the same error as in Misplaced \omit. \multispan with \newcommand - it's just not that visible. The problem is that xstring's \IfEqCase is not expandable since it makes assignments to perform the comparison. Instead, using a trick from On testing two fully expanded character strings for equality, you can utilize pdfTeX's \pdfstrcmp to compare strings in an expandable way:

enter image description here

\documentclass[letterpaper,10pt]{article}
\makeatletter
\newcommand*{\condrow}[2]{%
  \ifnum\pdfstrcmp{#1}{l}=\z@ #2 & & \\
  \else\ifnum\pdfstrcmp{#1}{r}=\z@ & & #2 \\
  \else\ifnum\pdfstrcmp{#1}{c}=\z@ & #2 & \\
  \else\ifnum\pdfstrcmp{#1}{m}=\z@ \multicolumn{3}{c}{#2} \\
  \else\PackageError{condrow}{Undefined option: #1}{}%
  \fi\fi\fi\fi%
}
\makeatother

\begin{document}
\begin{tabular}{|c|c|c|}
  \condrow{l}{left}
  \condrow{r}{right}
  \condrow{c}{center}
  \multicolumn{3}{c}{manual multi} \\ % WORKS
  \condrow{m}{condrow multi} % WORKS
\end{tabular}
\end{document}
Moriambar
  • 11,466
Werner
  • 603,163
3

An expl3 solution:

\documentclass[letterpaper,10pt]{article}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\condrow}{ m m }
 {
  \str_case:nnF { #1 }
   {
    { l } { #2 &    &    \\ }
    { r } {    &    & #2 \\ }
    { c } {    & #2 &    \\ }
    { m } { \multicolumn{3}{c}{#2} \\ }
   }
   { \PackageError{condrow}{Undefined~option:~#1}{<explanation>} }
 }
\ExplSyntaxOff

\begin{document}
\begin{tabular}{|c|c|c|}
  \condrow{l}{left}
  \condrow{r}{right}
  \condrow{c}{center}
  \condrow{m}{condrow multi}
\end{tabular}
\end{document}

This has the advantage of being more easily extended to accept new options.

enter image description here

egreg
  • 1,121,712
0

For information, if you use {NiceTabular} of nicematrix, with its built-in command \Block instead of \multicolumn, you have directly the output you wish (because \Block is a protected command which works as is).

However, you need several compilations because nicematrix uses PGF/Tikz nodes under the hood.

\documentclass[letterpaper,10pt]{article}
\usepackage{nicematrix}
\usepackage{xstring}

\newcommand*{\condrow}[2]{ \IfEqCase{#1}{ {l}{#2 & & \} {r}{ & & #2 \} {c}{ & #2 & \} {m}{\Block{1-3}{#2} & & \} }[\PackageError{condrow}{Undefined option: #1}{}] }

\begin{document} \begin{NiceTabular}{|c|c|c|} \condrow{l}{left} \condrow{r}{right} \condrow{c}{center} \multicolumn{3}{c}{manual multi} \ \condrow{m}{condrow multi} \end{NiceTabular} \end{document}

Output of the above code

F. Pantigny
  • 40,250