4

I encountered a very strange problem today.

I want to fill tables with automatic generated data. Hence, I designed a macro, which takes four arguments (one being optional). Arguments No. 1 and 4 are allowed to be empty, therefore I put an \ifx#1\@empty test into my code.

This is my macro in the first version:

\newcommand{\admin}[4][]{%
  #2&#3&
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    yes
  \else
    & no
  \fi%
  \\%
}

I was very surprised to find, that LaTeX didn't compile. This was the result:

! Extra \fi.
\\admin ...ldap @empty \relax yes \else & no \fi
\\
! Incomplete \ifx; all text was ignored after line 51.
< inserted text>
\fi

After two hours fiddling, I found out, that the ampersand causes all the trouble. This macro works without LaTeX throwing an error:

\newcommand{\admin}[4][]{%
  #2&#3&
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    yes
  \else 
    no
  \fi%
  \\%
}

The disadvantage is, that the word "No" is now standing in the wrong column. :-( My MWA (Minimal Work Around) is now as follows, but I'd like to know, what went wrong and how to avoid the additional if-clause I came up with.

\documentclass{article}

\makeatletter
%% This did not work due to the "&".  Removing the ampersand will get
%% the macro working, but than the word "No" from the ifclause will be
%% printed in the wrong column.
% \newcommand{\admin}[4][]{%
%   #2&#3&
%   \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
%   \def\@ldap{#1}\ifx\@ldap\@empty\relax
%     yes
%   %% The error starts here.  Comment out the next two lines, and the
%   %% error vanishes.  Remove the ampersand & and its also gone!
%   \else
%     & no
%   %% This would work
%   % \else 
%   %   no
%   \fi%
%   \\%
% }

%% Now: this works, but you have to have an extra if-clause!
\newcommand{\admin}[4][]{%
  #2&#3&%
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi&%
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    Yes
  \fi
  &
  \newcommand{\admin}[4][]{%
  #2&#3&%
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi&%
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    Yes
  \fi
  &
  \ifx\@ldap\@empty\relax\else
    No
  \fi%
  \\%
\def\@ldap{#1}\ifx\@ldap\@empty\relax\else
    No
  \fi%
  \\%
}
\makeatother

\begin{document}
  \begin{tabular}{@{}lllcc@{}}
    \hline
    \multicolumn{2}{@{}c}{Anwender}
    & \multicolumn{1}{c}{RZ-ID}
    & \multicolumn{2}{c@{}}{LDAP} \\
    \multicolumn{1}{@{}c}{Vorname}
    & \multicolumn{1}{c}{Nachname}
    &
    & \multicolumn{1}{c}{Yes}
    & \multicolumn{1}{c@{}}{No} \\
    \hline
    \admin{First}{Lastname}{fl19}
    \admin{Some}{Othername}{so97}
    \admin[false]{Not}{Listed}{}
    \hline
  \end{tabular}
\end{document}

PS.: This is a minimal example. In my real document, the macro is way more elaborative, as I added a lot more info to the second-last and last column. Therefore, a suggestion, to use \multicolumn{2}{c}{Yes} or \multicolumn{2}{c}{NO}, spanning the last two columns to avoid the ampersand, is no option to me.

  • 2
    A conditional cannot straddle alignment cells. – egreg Dec 10 '19 at 15:37
  • @egreg Thank you for your advice. – Jan Dec 10 '19 at 16:05
5

Note that in your actual MWA (I like that! :-D) you are getting

enter image description here

which probably isn't the intended result. The reason behind it is the same as the reason why your first solution fails: cells are groups, and your \def\@ldap is restricted to the fourth column. You should use \gdefinstead to have it working.

Personally I see no point in avoiding the double \if at all costs but this would be a possible way

\newcommand{\admin}[4][]{%
  #2&#3&%
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi &
  \def\@ldap{#1}%
  \ifx\@ldap\@empty\relax % I prefer \if\relax\detokenize{#1}\relax
     \def\@tempa{\textcolor{green}{\ding{51}}&}%
  \else
     \def\@tempa{&\textcolor{red}{\ding{55}}}%
  \fi
  \@tempa
  \\
}

enter image description here

Basically, the \if just sets the definition of\@tempa, which is expanded only after the \if has been worked out.

  • Very cool and helpful answer. – Jan Dec 10 '19 at 16:08
4

Conditionals cannot straddle alignment cells, but you can remove the conditional before issuing &; the technique uses \@firstoftwo and \@secondoftwo. See Why the \expandafter\@firstoftwo idiom?

\documentclass{article}

\makeatletter

\newcommand{\admin}[4][]{%
  #2&#3&%
  \if\relax\detokenize{#4}\relax
    ./.%
  \else
    #4%
  \fi&%
  \if\relax\detokenize{#1}\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {Yes}{&No}%
  \\%
}
\makeatother

\begin{document}
  \begin{tabular}{@{}lllcc@{}}
    \hline
    \multicolumn{2}{@{}c}{Anwender}
    & \multicolumn{1}{c}{RZ-ID}
    & \multicolumn{2}{c@{}}{LDAP} \\
    \multicolumn{1}{@{}c}{Vorname}
    & \multicolumn{1}{c}{Nachname}
    &
    & \multicolumn{1}{c}{Yes}
    & \multicolumn{1}{c@{}}{No} \\
    \hline
    \admin{First}{Lastname}{fl19}
    \admin{Some}{Othername}{so97}
    \admin[false]{Not}{Listed}{}
    \hline
  \end{tabular}
\end{document}

I also removed the two auxiliary macros, preferring a different safe test for emptiness.

enter image description here

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.