Conditional formatting in \newcommand

1,144

Solution 1

If arguments 2 and/or 3 are blank, they are omitted, along with the space that follows.

\documentclass{article}
\newcommand{\entry}[4]{\framebox(7,7){}\hspace{.75em}\markboth{#1}{#1}\textbf{#1}\ %
\ifx\relax#2\relax\else{(#2)}\ \fi%
\ifx\relax#3\relax\else\textit{#3}\ \fi%
$\bullet$\ {#4}}
\begin{document}
\entry{Purfling}{pur-fling}{Guitar Part}{Definition}

\entry{Neck}{}{}{Definition}
\end{document}


Solution 2

Here comes some sort of safety-belt with(out eTeX) bloatware:

\documentclass{article}
\makeatletter
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \@CheckWhetherNull{<Argument which is to be checked>}%
%%                   {<Tokens to be delivered in case that argument
%%                     which is to be checked is empty>}%
%%                   {<Tokens to be delivered in case that argument
%%                     which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%%
%% A concern in his posting is that the argument is hit with \string
%% after some expansions which in edge cases might result in unbalancing
%% surrounding \if..\fi-constructs if the macro is used inside of such
%% \if..\fi-constructs.
%%
%% That challenging concern sickened me. ;-)
%%
%% Therefore I decided to implerment a variant where this cannot happen
%% as expansion is forced by \romannumeral:
%%
%% After the first expansion-step, \string is not applied yet.
%% After the second expansion-step, any possibly disturbing remainders
%% are already removed due to \romannumeral-expansion.
%%
%% No eTeX- or whatsoever extensions. No \if.. .Only \romannumeral,
%% digit 0, space token for terminating \romannumeral-expansion,
%% \string, \expandafter, \@firstoftwo, \@secondoftwo, {, }.
%%
%% May 20, 2016
%%
%% Ulrich Diez (e-mail: [email protected])
%%
\newcommand\@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
\@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%
%%----------------------------------------------------------------------
%% Check whether argument is blank (empty or only spaces):
%%......................................................................
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" _un_delimited arguments: --
%% \@CheckWhetherBlank{<Argument which is to be checked>}%
%%                    {<Tokens to be delivered in case that
%%                      argument which is to be checked is blank>}%
%%                    {<Tokens to be delivered in case that argument
%%                      which is to be checked is not blank}%
\newcommand\@CheckWhetherBlank[1]{%
\romannumeral\expandafter\expandafter\expandafter\@secondoftwo
\expandafter\@CheckWhetherNull\expandafter{\@firstoftwo#1{}.}%
}%
%%----------------------------------------------------------------------
%%
\newcommand{\entry}[4]{%
\framebox(7,7){}\hspace{.75em}\markboth{#1}{#1}\textbf{#1}\ %
\@CheckWhetherBlank{#2}{}{(#2)\ }%
\@CheckWhetherBlank{#3}{}{\textit{#3}\ }%
$\bullet$\ {#4}%
}%
\makeatother
\begin{document}
\entry{Purfling}{pur-fling}{Guitar Part}{Definition}

\entry{Neck}{}{ }{Definition}
\end{document}


The crucial point is:

It is tested whether arguments do consist only of space tokens or no tokens at all. It is not tested whether expanding arguments yields visible material and not just glue or "voidness".

In other words: Things like \entry{Neck}{\empty}{\empty}{Definition} might require another "safety-belt".

Solution 3

You have also to gobble the spaces, when the argument is void:

\documentclass{article}

\newcommand{\IfNotBlank}[2]{%
\if\relax\detokenize{#1}\relax\else#2\fi
}

\newcommand{\entry}[4]{%
\framebox(7,7){}%
\hspace{.75em}%
\markboth{#1}{#1}%
\textbf{#1}\ %
\IfNotBlank{#2}{(#2)\ }%
\IfNotBlank{#3}{\textit{#3}\ }%
$\bullet$\ {#4}%
}

\begin{document}

\entry{Purfling}{pur-fling}{Guitar Part}{Definition}

\entry{Neck}{}{}{Definition}

\end{document}


You may want to look at a key-value interface:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\entry}{mm}
{
\group_begin:
\keys_set:nn { kale/dict } { #1 }
\framebox(7,7){} \hspace{.75em}
\markboth{\l_kale_dict_main_tl}{\l_kale_dict_main_tl}
\textbf{\l_kale_dict_main_tl}~
\tl_if_blank:VF \l_kale_dict_hyphen_tl
{
(\l_kale_dict_hyphen_tl)~
}
\tl_if_blank:VF \l_kale_dict_note_tl
{
\textit{\l_kale_dict_note_tl}~
}
\textbullet{}~
#2
\group_end:
}

\keys_define:nn { kale/dict }
{
main   .tl_set:N = \l_kale_dict_main_tl,
hyphen .tl_set:N = \l_kale_dict_hyphen_tl,
note   .tl_set:N = \l_kale_dict_note_tl,
}

\ExplSyntaxOff

\begin{document}

\entry{
main=Purfling,
hyphen=pur-fling,
note=Guitar Part,
}{Definition}

\entry{
main=Neck,
}{Definition}

\end{document}

Share:
1,144

Author by

Kale

I'm a classical guitarist and guitar instructor who got comfortable with moving past the GUI via learning Lilypond, a free music notation software program that uses a markup language. The next thing I learned was html and css, with which I built my own website (which helped me become a self-employed guitar instructor). I've since used a bit of bash, php, mysql, latex, and python for a mix of fun and as a way of increasing value for my guitar students.

Updated on May 20, 2020

• Kale over 2 years

I'm using the following from a dictionary template:

\newcommand{\entry}[4]{\framebox(7,7){}\hspace{.75em}\markboth{#1}{#1}\textbf{#1}\ {(#2)}\ \textit{#3}\ $\bullet$\ {#4}}

\entry{Purfling}{pur-fling}{Guitar Part}{Definition}

\entry{Neck}{}{}{Definition}


Produces

Purfling (pur-fling) Guitar Part * Definition

Neck () * Definition


I'd like the second element (the parenthesis) to appear only if there is text inside it:

Purfling (pur-fling) Guitar Part * Definition

Neck * Definition

• Steven B. Segletes over 6 years
I see our approaches are essentially the same, packaged slightly differently. But I was wondering, what does the \detokenize buy you?
• Steven B. Segletes over 6 years
I suppose if one passed \relax as an argument, that would produce different results, but that is not really a usage case here.
• egreg over 6 years
@StevenB.Segletes Safety belt. ;-)
• egreg over 6 years
Note that \if is quite risky, as it triggers expansion of the first token in #2, if not empty. Not really a big deal, but if the expansion starts with \relax, as some macros do…
• Steven B. Segletes over 6 years
@egreg "Quite" risky for those who don't wear safety belts, eh? I suppose \ifx would be "safer"? Then, you'd have to purposefully aim at your foot with a \relax in order to shoot it.
• Steven B. Segletes over 6 years
Welcome to the site! "Bloatware" (tee-hee)... I hear the flamethrowers starting up. By the way, that is an impressive expansion.
• Steven B. Segletes over 6 years
My apologies. My welcome is sincere, and I know what you mean, in striving for the elegance of no-frills code.
• egreg over 6 years
Of course! On the other hand, the \tl_if_blank:VF approach also allows { } (that is, spaces sneaking in).
• user106072 over 6 years
@StevenB.Segletes Thanks for welcoming me, but please strictly stick to the subject! ;-> Some parts of my remark are enclosed in parentheses for making clear what the term "bloatware" does (not) refer to. Nowadays the "impressive expansion" is bloatware. Nonetheless it is fun. The gist of \@CheckWhetherNull comes from Robert R Schneck's \ifempty-macro.