5

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
3

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

  • 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… – egreg May 19 '16 at 18:06
  • @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 May 19 '16 at 18:15
  • Of course! On the other hand, the \tl_if_blank:VF approach also allows { } (that is, spaces sneaking in). – egreg May 19 '16 at 19:38
2

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}
  • I see our approaches are essentially the same, packaged slightly differently. But I was wondering, what does the \detokenize buy you? – Steven B. Segletes May 19 '16 at 17:54
  • I suppose if one passed \relax as an argument, that would produce different results, but that is not really a usage case here. – Steven B. Segletes May 19 '16 at 17:59
  • 1
    @StevenB.Segletes Safety belt. ;-) – egreg May 19 '16 at 18:01
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: ud.usenetcorrespondence@web.de)
%%
\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".

  • Welcome to the site! "Bloatware" (tee-hee)... I hear the flamethrowers starting up. By the way, that is an impressive expansion. – Steven B. Segletes May 19 '16 at 19:08
  • My apologies. My welcome is sincere, and I know what you mean, in striving for the elegance of no-frills code. – Steven B. Segletes May 19 '16 at 19:24
  • 1
    @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. – user106072 May 19 '16 at 19:50

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.