31

I am trying to fix some problems with the accessibility.sty package from www.babs.gmxhome.de

There is one string comparison which always results to false, i.e. the language code definition will not be executed.

\ifthenelse{\equal{#1}{\string german}}{\gdef\LanguageCode{/Lang(DE)}}{}%

Now if I try

\message{#1}
\message{\string german}

The output when compiling a document will be:

german german

I am really lost, why #1 and the string german do not compare to true here... What could be the reason?

5
  • 1
    Why have you got \string here? That gives a catcode-12 ('other') g and then catocde-11 ('letter') erman. I have a feeling you are imagining that the two arguments are the same just because the letters look identical when you typeset them.
    – Joseph Wright
    Commented Aug 8, 2014 at 15:56
  • I am not sure, if I understand your comment. Afaik \string takes a token and returns a string of characters, no?!
    – ndbd
    Commented Aug 8, 2014 at 16:27
  • @nbd: Better use xstring package for example
    – user31729
    Commented Aug 8, 2014 at 16:41
  • I tried, i.e. message{#1}, \IfStrEq{#1}{\string german}{message{moo}}{} which results in output "german". I just don't get this
    – ndbd
    Commented Aug 8, 2014 at 16:56
  • 1
    Can you show how you use this? It's important to know what argument you're passing to \equal as #1.
    – egreg
    Commented Aug 8, 2014 at 17:21

3 Answers 3

35

The \ifthenelse test does a token-based comparison. Thus when you do

\documentclass{article}
\usepackage{ifthen}
\newcommand{\foo}[1]{%
  \ifthenelse{\equal{#1}{\string german}}
    {TRUE}
    {FALSE}%
}
\begin{document}

\foo{german}

\end{document}

what happens is that \string is applied to the first token it sees, in this case a g. Comparing the two results, they are not the same: one has one non-letter then five letters, the second has six letters. Typesetting those two cases is different: g with category code 12 ('other') typesets the same glyph as g with category code 11 ('letter'), so the two look the same.

There are various approaches to doing true 'string' comparisons in TeX. With a modern TeX engine, by far the easiest is to use \pdfstrcmp or equivalent:

\documentclass{article}
\usepackage{pdftexcmds}
\makeatletter
\newcommand\foo[1]{%
  \ifnum\pdf@strcmp{\unexpanded{#1}}{german}=0 %
     \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
    {TRUE}
    {FALSE}%
}
\makeatother
\begin{document}

\foo{german}

\end{document}

This does do a string comparison, ignoring category codes. If you want to stick with \ifthenelse but can assume e-TeX then

\documentclass{article}
\usepackage{ifthen}
\newcommand{\foo}[1]{%
  \ifthenelse{\equal{\detokenize{#1}}{\detokenize{german}}}
    {TRUE}
    {FALSE}%
}
\begin{document}

\foo{german}

\end{document}

will work as \detokenize makes its entire argument into a string.

Another approach without needing anything other than classical TeX primitives is to use something like

\documentclass{article}
\usepackage{pdftexcmds}
\makeatletter
\newcommand\foo[1]{%
  \begingroup
    \def\@tempa{#1}%
    \@onelevel@sanitize\@tempa
    \def\@tempb{german}%
    \@onelevel@sanitize\@tempb
    \ifx\@tempa\@tempb
       \aftergroup\@firstoftwo
    \else
      \aftergroup\@secondoftwo
    \fi
  \endgroup
    {TRUE}
    {FALSE}%
}
\makeatother
\begin{document}

\foo{german}

\end{document}

using the fact that \@onelevel@sanitize also converts things to strings.

Of course, if you know that the input will be something sensible, there's no real need to use any detokenization at all

\documentclass{article}
\usepackage{ifthen}
\newcommand{\foo}[1]{%
  \ifthenelse{\equal{#1}{german}}
    {TRUE}
    {FALSE}%
}
\begin{document}

\foo{german}

\end{document}
3
  • 1
    Thanks very much for this insightful and detailed explanation. Indeed, just leaving out \string is sufficient, since the input is already (or can assumed to be) sensible. I really was under the impression that "german" would be considered as one token. Again, thanks!
    – ndbd
    Commented Aug 8, 2014 at 20:29
  • @ndbd Are you perhaps a programmer is some other language (C?): TeX's idea of a 'token' tends to confuse such people, as it's not really the same concept.
    – Joseph Wright
    Commented Aug 8, 2014 at 21:56
  • Plenty of experience in OCaml, C, some python... Yes. TeX is certainly different :-)
    – ndbd
    Commented Aug 9, 2014 at 20:48
2

Another option is to use package etoolbox (which works with XeLaTeX), here is an MWE

\documentclass{article}

\usepackage{etoolbox}

\begin{document}
\renewcommand{\language}{german}
\ifdefstring{\language}{german}{German}{Other}
\\

\renewcommand{\language}{english}
\ifdefstring{\language}{german}{German}{Other}
\end{document}

which produces

german

The advantage of using \ifdefstring is that, you can leave the curly braces empty to "do nothing"

\ifdefstring
{\language}{german}
{German}
{} %% do nothing
2
  • What if the second argument "german" is white space ({}) ? How would you make it work? (I tried using {} but it doesn't work)
    – Peluche
    Commented Nov 16, 2022 at 14:46
  • @Peluche The second argument is the condition, if it is empty, you will end up having nothing to compare the value of \language with. Please look at the documentation for more details.
    – zyy
    Commented Nov 20, 2022 at 1:02
1

I would like to add another simple way of making a string-based choice in plain TeX without the need for additional packages. It makes use of the TeX macro expansion and uses \csname ... \endcsname to build a macro name.

\documentclass[11pt,a4paper]{article}

\makeatletter
% define macros that are executed for every given string
\def\setlang@english{\gdef\LanguageCode{/Lang(EN)}}
\def\setlang@german{\gdef\LanguageCode{/Lang(DE)}}
\def\setlang@dutch{\gdef\LanguageCode{/Lang(NL)}}
\newcommand{\setlang}[1]{
  % call the macro corresponding to argument #1
  \csname setlang@#1\endcsname
}
\makeatother

% test the macro
\begin{document}
  \setlang{english}
  \LanguageCode
  \setlang{dutch}
  \LanguageCode
\end{document}
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .