3

In a book I'm writing, I use the \IfStrEqCase from the xstring package in a command to organize access to several pieces of information I need throughout the document, without having to define a separate command for each. One of the keys is the edition/version of the book. Obviously, as this is liable to change, it's convenient to have this data localized to a single place.

In the colophon of the book, I have a copyright notice which includes the name of the book and the aforementioned edition number. I'm a big fan of the nth package, and use it elsewhere in my document. However, when I try to combine it with my command, I get compilation errors. Here's an MWE which demonstrates the error:

\documentclass{article}

\usepackage{xstring}
\usepackage{nth}

\DeclareRobustCommand{\Gkeys}[1]{%
    \IfStrEqCase{#1} {%
        {edition}{10}%
        {author}{John Doe}%
        {title}{Title of My Book}%
    }[\textbf{??key not found??}]%
}

\begin{document}

\textbf{\Gkeys{title}}, \textsc{\nth{\Gkeys{edition}} Edition}\\
\Gkeys{author} 2017

\end{document}

When I try to compile this document with pdflatex I get the following error:

! Missing number, treated as zero.
<to be read again> 
                   \protect 
l.16 ...}}, \textsc{\nth{\Gkeys{edition}} Edition}
                                                  \\
?

I'm not sure what's going here to make this not work. If I define a simple command, like say \def\BookEditionNumber{10}, this works fine, but obviously that loses the convenience of the \Gkeys command I had declared.

EDIT:

A comment pointed out that since I declared \GKeyswith \DeclareRobusCommand, I rendered it unexpandable, and thus \nth can't do anything with it. My impetus for doing so was to allow it to work with commands like \section. However, out of curiosity, I changed the command to be declared with \newcommand instead. Interestingly, this also failed to work. When I tried to compile that document, I got the following error:

! Missing number, treated as zero.
<to be read again> 
                   \let 
l.16 ...}}, \textsc{\nth{\Gkeys{edition}} Edition}
                                                  \\
? 
  • You declared \GKeys as robust command, this isn't expandable and \nth can do nothing here – user31729 Mar 14 '17 at 6:24
  • I see. The reason I did that was to make it work with commands like \section. Is there any way to get it both ways? – Kevin Keith Mar 14 '17 at 6:26
  • Well, \IfStrEqCase seems to be unexpandable as well, so even if \Gkeys is not robust the next cause of mischief is \IfStrEqCase – user31729 Mar 14 '17 at 6:28
3

\IfStrEqCase isn't expandable, so even if \Gkeys would be expandable itself, the inner command isn't.

I suggest to use the expandable \str_case:nnF command from the package expl3 for the checking, the syntax is almost the same compared to \IfStrEqCase.

The only thing to consider is that spaces are gobbled in the \ExplSyntaxOn...\ExplSyntaxOff domain. It is possible to use ~ here which acts as normal space token then (and not as non-breakable space)

\documentclass{article}

\usepackage{xstring}
\usepackage{nth}

\usepackage{expl3}

\ExplSyntaxOn
\newcommand{\Gkeys}[1]{%
  \str_case:nnF {#1} {
    {edition}{10}%
    {author}{John~Doe}%
    {title}{Title~of~My~Book}%
  }{\textbf{??key~not~found??}}%
}
\ExplSyntaxOff

\begin{document}
\textbf{\Gkeys{title}}

\nth{\Gkeys{edition}}

\textsc{\nth{\Gkeys{edition}} Edition}

\Gkeys{author} 2017

\section{\Gkeys{author} 2017}

\end{document}

enter image description here

  • Does the tilde, in this instance, cause a regular space, or a non-breaking space to be inserted? – Kevin Keith Mar 14 '17 at 6:39
  • Hmm, is there a way to insert a space without it being non-breaking? – Kevin Keith Mar 14 '17 at 6:51
  • Backslash + space os is a normal space, as in \ . – Dr. Manuel Kuehner Mar 14 '17 at 7:16
  • 1
    @ChristianHupfer What do you mean? In an \ExplSyntaxOn context, ~ denotes a normal space token, not the usual tie. – egreg Mar 14 '17 at 8:09
  • @egreg: Yes, sure. I typed on my smart phone and was on the way to leave the appartment. Of course ~ is the non-breakable space in non-expl3 - context – user31729 Mar 14 '17 at 8:47
3

You can use a handier interface such as

\defineset{my}{
  author=John Doe,
  title=Title of my book,
  edition=10,
}

In the macros below, you can define as many sets as you want; I also show how to define an abbreviated form like \Gkeys as an alias for \getkey{my}.

\documentclass{article}
\usepackage{xparse}
\usepackage{nth}

\ExplSyntaxOn
\NewDocumentCommand{\defineset}{mm}
 {
  \prop_set_eq:NN \l__keith_set_temp_prop \g_keith_set_initial_prop
  \keys_set:nn { keith/set } { #2 }
  \prop_new:c {g_keith_set_#1_prop}
  \prop_gset_eq:cN {g_keith_set_#1_prop} \l__keith_set_temp_prop
 }
\NewExpandableDocumentCommand{\getkey}{mm}
 {
  \prop_item:cn {g_keith_set_#1_prop} { #2 }
 }
\keys_define:nn { keith/set }
 {
  author  .code:n = \prop_put:Nnn \l__keith_set_temp_prop { author } { #1 },
  title   .code:n = \prop_put:Nnn \l__keith_set_temp_prop { title } { #1 },
  edition .code:n = \prop_put:Nnn \l__keith_set_temp_prop { edition } { #1 },
 }
\prop_new:N \l__keith_set_temp_prop
\prop_new:N \g_keith_set_initial_prop
\prop_gput:Nnn \g_keith_set_initial_prop { author } { ??MISSING?? }
\prop_gput:Nnn \g_keith_set_initial_prop { title } { ??MISSING?? }
\prop_gput:Nnn \g_keith_set_initial_prop { edition } { ??MISSING?? }
\ExplSyntaxOff

\defineset{my}{
  author=John Doe,
  title=Title of my book,
  edition=10,
}
\defineset{another}{
  author=Jane Doe,
  title=Title of her book,
  edition=2,
}


\newcommand{\Gkeys}[1]{\getkey{my}{#1}}

\begin{document}

\textbf{\Gkeys{title}}

\nth{\Gkeys{edition}}

\textsc{\nth{\Gkeys{edition}} Edition}

\Gkeys{author} 2017

\section{\Gkeys{author} 2017}

\nth{\getkey{another}{edition}}

\end{document}

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.