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}

enter image description here

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:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% 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}

enter image description here

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

Related videos on Youtube

Kale
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

Comments

  • Kale
    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
    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
    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
    egreg over 6 years
    @StevenB.Segletes Safety belt. ;-)
  • egreg
    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
    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
    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
    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
    egreg over 6 years
    Of course! On the other hand, the \tl_if_blank:VF approach also allows { } (that is, spaces sneaking in).
  • user106072
    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.