5

I have a command \mycom{} which takes 1 argument. The command should perform a test on the argument and do something accordingly. For simple arguments, I can use \ifthenelse, but I need to consider more general arguments, e.g. containing commands or environments. The following MWE follows a solution for a more robust string test, which was given in this post:

\documentclass{article}
\makeatletter
\newcommand{\strtest}[2]{%
\ifnum\pdfstrcmp{#1}{#2}=\z@
  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi}
\makeatother

\newcommand{\mycom}[1]{%
\strtest{#1}{}%
{content :  empty}%
{content : #1}%
}

\begin{document}
\mycom{}

\mycom{coucou}
\end{document}

This works. But if i try to call \mycom{\textbf{coucou}}, then the compilation fails.

1
  • Ah, now I see! The quoted answer tells you that this test works only for simple strings, and suggests a way to cope with more complicated input.
    – egreg
    Feb 6, 2012 at 15:49

2 Answers 2

6

The \pdfstrcmp primitive fully expands its argument. Thus things go wrong with macros that cannot be expanded, which includes \textbf. You can prevent this using the \unexpanded primitive:

\newcommand{\strtest}[2]{%
  \ifnum\pdfstrcmp{\unexpanded{#1}}{\unexpanded{#2}}=\z@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
12
  • BTW, if you want this to work cross-engine, you should load the pdftexcmds package and use \pdf@strcmp, which deals with the fact that XeTeX calls the primitive \strcmp and LuaTeX requires it is implemented in Lua.
    – Joseph Wright
    Feb 6, 2012 at 16:06
  • Would you prefer \unexpanded or \detokenize in this case?
    – egreg
    Feb 6, 2012 at 16:09
  • @egreg We've used \unexpanded in LaTeX3, as the idea is to prevent expansion rather than turn into a string per se (which happens anyway). That I know of, there is no technical reason to prefer one approach over another.
    – Joseph Wright
    Feb 6, 2012 at 16:16
  • So I guess this can be closed as a duplicate, as your answer is already included in mine.
    – egreg
    Feb 6, 2012 at 16:19
  • 1
    @egreg, Joseph, there is one technical reason to prefer \unexpanded: it is slightly more efficient since we move around less tokens: \pdfstrcmp converts the tl to a string internally, rather than having to first produce character tokens. For instance, \edef\x{\exp_not:c{\prg_replicate:nn{100000}x}} \edef\x{\prg_replicate:nn{1000}\x} \str_if_eq:xxTF{\tl_to_str:N\x}{}{}{} blows up when trying to build a string with 100002000 tokens, whereas using \exp_not:o works fine. Feb 6, 2012 at 18:39
3

I want to show an alternative. Based on the LaTeX3 engine one approach is:

\documentclass{article}
\usepackage{xparse,expl3,}
\ExplSyntaxOn

\NewDocumentCommand{ \mycom } { m } {
 \tl_if_empty:nTF { #1 }
   {content:~empty}
   {content:~#1}
}
\ExplSyntaxOff
\begin{document}
\mycom{}

\mycom{coucou}

\mycom{\textbf{coucou}}
\end{document}

Base on the comments question you can compare strings with:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\mystringcase}{  m }
  {
    \prg_case_str:nnn { #1 }
         {
          { a }  { Your~string~\textbf{a} }
          { b }  { Your~string~\textbf{b} }
          { c }  { Your~string~\textbf{c} }
         }       
         { Not~in~list }
  }
\ExplSyntaxOff
\begin{document}
\mystringcase{a}

\mystringcase{b}

\mystringcase{d}
\end{document}
3
  • Why not use \tl_if_empty:nTF?
    – Joseph Wright
    Feb 6, 2012 at 16:35
  • @JosephWright: Because of the Argument #1 I don't know the contents and I want to avoid unwanted expansion. Feb 6, 2012 at 16:46
  • \tl_fi_empty:nTF does no expansion, and is therefore safe with any input.
    – Joseph Wright
    Feb 6, 2012 at 17:05

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.