5

This has been answered here for text outputs with the use of \IfEqCase from the xstring package. But if I want to use the output as a value to set a parameter in a function, it fails.

Here is my MWE:

\documentclass[a4paper]{article} 

\usepackage{lettrine,xstring}

\newcommand*{\Lettrine}[1]{%
    \lettrine[lines=1, findent=\IfEqCase{#1}{%
        {P}{-0.8em}%
        {Q}{1em}%
    }[\PackageError{Lettrine}{Undefined option to Lettrine: #1}{}]%
    ]{\textit{#1}}{}%
}

\newcommand*{\LettrineSimply}[1]{\lettrine[lines=1, findent=-0.8em]{\textit{#1}}{}}

\begin{document} 
\LettrineSimply{P} erfectly working !
\Lettrine{P} ossibly it will work !
\end{document}

\LettrineSimply works, but I want to use different findent depending on the letter. In my attempt with the use of \IfEqCase, I have the following compilation error:

$ pdflatex MWE_lettrine_command.tex 
This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013)
 restricted \write18 enabled.
entering extended mode
(./MWE_lettrine_command.tex
LaTeX2e <2011/06/27>
Babel <3.9f> and hyphenation patterns for 15 languages loaded.
(/usr/share/texmf-dist/tex/latex/base/article.cls
Document Class: article 2007/10/19 v1.4h Standard LaTeX document class
(/usr/share/texmf-dist/tex/latex/base/size10.clo))
(/usr/share/texmf-dist/tex/latex/lettrine/lettrine.sty
(/usr/share/texmf-dist/tex/latex/graphics/keyval.sty)
Loading lettrine.cfg
(/etc/texmf/tex/latex/lettrine.d/lettrine.cfg))
(/usr/share/texmf-dist/tex/generic/xstring/xstring.sty
(/usr/share/texmf-dist/tex/generic/xstring/xstring.tex))
(./MWE_lettrine_command.aux)
! Missing number, treated as zero.
<to be read again> 
                   \let 
l.17 \Lettrine{P}
                  ossibly it will work !
? 

If I just ENTER:

! Illegal unit of measure (pt inserted).
<to be read again> 
                   \let 
l.17 \Lettrine{P}
                  ossibly it will work !

Do I try to assign a string to the findent parameter? How can I solve that?

Otherwise, is it possible to define tables or associative maps inside commands?

5

As your \Lettrine command certainly does some un-expandable things, we don't really need a fully expandable version of \IfEqCase.

lettrine

\documentclass[a4paper]{article} 

\usepackage{lettrine,xstring}

\makeatletter
\newcommand*{\Lettrine}[1]{%
    \IfEqCase{#1}{%
        {P}{\def\@@temp{findent=-0.8em,}}%
        {Q}{\def\@@temp{findent=1em,}}%
    }[\PackageError{Lettrine}{Undefined option to Lettrine: #1}{}%
      \def\@@temp{}]%
    \expandafter\lettrine\expandafter[\@@temp lines=1]{\textit{#1}}{}%
}
\makeatother

\newcommand*{\LettrineSimply}[1]
   {\lettrine[lines=1, findent=-0.8em]{\textit{#1}}{}}

\begin{document}\thispagestyle{empty}

\LettrineSimply{P} erfectly working !
\Lettrine{P} ossibly it will work !
\Lettrine{Q} uite certainly it does work !
%\Lettrine{R} arely are errors encountered ! % generates error as expected
\end{document}
5

This is more of a comment on wipet's answer but is a bit too long.

Here is another way to do an expandable \ifeqcase. The conditions are the same: we only compare single tokens. We use \eqifcase as name.

Added note: initial motivation in revisiting wipet's interesting \ifeqcase was to move the execution of the selected branch to after the case-switch has been cleared. This being done it is just one step to make the \eqifcase into a macro which expands in only two steps, before executing the selected code. And another aspect (independent of the added "expand in only two steps") worth pointing out is that \eqifcase can be used as argument to macros which expand their argument via \romannumeral-`0. I have added an illustration of this below.

eqifcase

\documentclass{article}

\def\eqifcase #1#2#3{\eqifcaseA #1#2#1{#3}\end }

\def\eqifcaseA #1#2#3{\ifx #1#2\eqifcaseDo{#3}\fi \eqifcaseA #1}

\def\eqifcaseDo #1\fi #2\end{\fi #1}

\def\test #1{%
    \eqifcase {#1}{{A}{aa}{B}{bb}{C}{cc}}{not found}}


\begin{document}\thispagestyle{empty}
\test{A}

\test{B}

\test{C}

\test{D}
\end{document}

Illustration (using within macros expanding their arguments via f-expansion) and Extension (case-switch expands in only two steps; this aspect is not illustrated here)

\documentclass{article}

\def\eqifcase #1#2#3{\romannumeral0\eqifcaseA #1#2#1{#3}\end }

\def\eqifcaseA #1#2#3{\ifx #1#2\eqifcaseDo{#3}\fi \eqifcaseA #1}

\def\eqifcaseDo #1\fi #2\end{\fi \space #1}

\usepackage {xintfrac}

\makeatletter
\newcommand{\DOOPERATION}[1]{\eqifcase {#1}
    {+\xintAdd
     *\xintMul
     -\xintSub
     /\xintDiv
     T\xintTrunc}{\@gobbletwo}}
\makeatother

\begin{document}

Demonstrating the use within macros applying f-expansion to their arguments:

\xintIrr {\DOOPERATION -{113/355}{22/7}}

\xintIrr {\DOOPERATION *{1024/243}{243/1024}}

\xintIrr {\DOOPERATION /{\DOOPERATION *{1001}{999}}{\DOOPERATION *{77}{111}}}

\DOOPERATION {T}{18}{113/355}


\end{document}

ifcase extended

  • OK, you have better code (only three lines) with the same result. – wipet May 20 '14 at 21:39
  • @wipet I have commented more on \eqifcase which was motivated by your interesting \ifeqcase – user4686 May 21 '14 at 7:13
4

You should use an expandable command as the value of findent, but \IfEqCase isn't. Here's a working version with xparse; I've added \ignorespaces so that it's immaterial if you leave a space after \Lettrine{P} or not.

\documentclass[a4paper]{article} 

\usepackage{lettrine,xparse}

\ExplSyntaxOn
\NewDocumentCommand{\Lettrine}{m}
 {
  \lettrine[lines=1, findent=\lalebarde_case:n { #1 }]{\textit{#1}}{}
  \ignorespaces
}

\cs_new:Npn \lalebarde_case:n #1
 {
  \str_case:nnF { #1 }
   {
    {P}{-0.8em}
    {Q}{1em}
   }
   {% none of the above
    \PackageError{Lettrine}{Undefined option to Lettrine: #1}{}
   }
 }
\ExplSyntaxOff

\newcommand*{\LettrineSimply}[1]{\lettrine[lines=1, findent=-0.8em]{\textit{#1}}{}\ignorespaces}

\begin{document} 
\LettrineSimply{P} erfectly working!

\Lettrine{P}erfectly working!

\Lettrine{Q}uestion: will it work?
\end{document}

You should be able to add whatever letter you want; the order is almost unimportant; for greater efficiency, put the most frequent letters first.

enter image description here

  • Thanks egreg, but it does not compile for me: ! Undefined control sequence. \lalebarde_case:n #1->\str_case:nnF {#1}{{P}{-0.8em}{Q}{1em}}{\PackageError ... l.30 \Lettrine{P} erfectly working! with pdflatex. – lalebarde May 20 '14 at 17:03
  • @lalebarde Update your TeX distribution. – egreg May 20 '14 at 17:09
  • I did a texhash, but it changes nothing. – lalebarde May 20 '14 at 17:15
  • Oh yes, I use texlive 2012 ! – lalebarde May 20 '14 at 17:16
  • @lalebarde TeX Live 2014 is to be released shortly. – egreg May 20 '14 at 17:18
4

You need the \ifeqcase to be defined as expandable macro. My solution uses only TeX primitives, no xparse package is needed:

\documentclass[a4paper]{article}
\usepackage{lettrine}

\def\ifeqcase#1#2{\ifeqcaseA#1#2\end}
\def\ifeqcaseA#1#2#3#4{%
   \ifx#1#2#3\expandafter\ifeqcaseE\expandafter#4%
   \else\ifx#4\end
        \else \expandafter\expandafter\expandafter
              \ifeqcaseA\expandafter\expandafter\expandafter#1%
                        \expandafter\expandafter\expandafter#4% 
   \fi \fi
}
\def\ifeqcaseE#1\end#2{}

\newcommand*{\Lettrine}[1]{%
    \lettrine[lines=1, findent=\ifeqcase{#1}{%
        {P}{-0.8em}% 
        {Q}{1em}%
    }{\PackageError{Lettrine}{Undefined option to Lettrine: #1}{}}%
    ]{\textit{#1}}{}%
}
\newcommand*{\LettrineSimply}[1]{\lettrine[lines=1, findent=-0.8em]{\textit{#1}}{}}

\begin{document}   
\LettrineSimply{P}erfectly working !
\Lettrine{P}ossibly it will work !
\Lettrine{Q}next test.
\end{document}

See that the different syntax is used for \ifcaseeq: the else part is in normal TeX braces.

I know that the question was LaTeX-type but we can compare the code which generates the same effect in plainTeX (using \eqifcase by @jfbu).

\input opmac

\def\eqifcase #1#2#3{\eqifcaseA #1#2#1{#3}\end}
\def\eqifcaseA #1#2#3{\ifx #1#2\eqifcaseE{#3}\fi \eqifcaseA #1}
\def\eqifcaseE #1\fi #2\end{\fi #1}

\def\letterfirst#1{\vskip.7\baselineskip\noindent{\it\thefontsize[24.7]#1}%
   \kern\eqifcase#1{P{-0.5em} Q{1em} R{.1em} S{.4em}}
   {0pt\opwarning{\string\letterfirs{#1} in unspaced}}%
}

\letterfirst Possibly it will work!
\letterfirst Qnext text.

\end

That is the beauty of TeX.

  • I cannot compile it: $ pdflatex MWE_lettrine_command3.tex This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013) [cutted] LaTeX2e <2011/06/27> Runaway argument? lines=1, findent=-0.8em {\textit {P}}{}erfectly working ! \Lettrine {\ETC. ! Paragraph ended before \@lettrine was complete. <to be read again> \par l.29 ? – lalebarde May 20 '14 at 18:19
  • I actually need at least 15 cases. – lalebarde May 20 '14 at 18:21
  • 1
    @lalebarde: I missed one square backet in the second \newcommand after findent=-0.8em while I copied and pasted my code to stackexchange. Sorry. I have corrected it now. – wipet May 20 '14 at 20:20
  • 1
    @egreg: You are not right. my macro \ifcaseeq works with arbirtary number of parameters. You can try it... – wipet May 20 '14 at 20:21
  • @wipet I was using the first version. Now it works as advertised. – egreg May 20 '14 at 20:48
1

Here is the final code, from jfbu solution, mixed with what I have learnt from wipet and egreg:

\documentclass{article}
\usepackage{lettrine}

\def\eqifcase #1#2#3{\eqifcaseA #1#2#1{#3}\end }

\def\eqifcaseA #1#2#3{\ifx #1#2\eqifcaseDo{#3}\fi \eqifcaseA #1}

\def\eqifcaseDo #1\fi #2\end{\fi #1}

\def\Lettrine #1{\vspace{-4ex}\lettrine[lines=1,findent=%
    \eqifcase {#1}{{P}{-0.8em}{T}{-0.6em}}{-0.1em}%
    ]{\textit{#1}}{}}


\begin{document}\thispagestyle{empty}
\section{section 1}
\Lettrine{P}owerfull macro !
\section{section 2}
\Lettrine{D}efault.
\section{section 3}
\Lettrine{T}remendous!
\section{section 4}
without lettrine to show that thanks to \textit{\\vspace\{-4ex\}} in the macro, we keep the same vertical space between the text baseline and the section title.
\end{document}

enter image description here Big thanks to all the three of you, you are amazing ! EDIT: update thanks to remarks.

  • 1
    you can remove the \expandafter in your \Lettrine... ;-) – user4686 May 21 '14 at 8:02
  • 1
    compiling the code with \vspace{-4ex} makes the big letters overlap on my installation – user4686 May 21 '14 at 8:05
  • @jfbu, yes, I have not changed the snapshot. Lettrines are intended to be used after sections. \vspace{-4ex} enables to keep the same space between the section title and the text, without consideration for the lettrine. – lalebarde May 21 '14 at 9:01
  • Updated. Of course, this vspace depends on the sections specifications. Here, 2ex would have been better. – lalebarde May 21 '14 at 9:13
  • you could perhaps use \smash to kill the vertical space occupied by the lettrine. No need for a \vspace then. – user4686 May 21 '14 at 10:28

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.