Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

EDIT: Simplified question

How can I make the following code print "Yes"?

\IfSubStr{\textbf{AAA}}{AAA}{Yes}{No}

Full question

I'm playing with xstring's IfSubStr, but I don't really understand how expansion works.

Here's a largely simplified MWE demonstrating my problem:

\documentclass{minimal}

\usepackage{xstring}

\newcommand{\correctanswer}{}
\newcommand{\mytext}[1]{
    Text :
    \noexpandarg
    \IfSubStr{#1}{\correctanswer}{
        \textbf{\boldmath #1}
    }{
        #1
    }
}
\newcommand{\mymathtext}[1]{\mytext{\ensuremath{#1}}}

\begin{document}
    \mytext{Foo} \mytext{Bar\correctanswer} \mymathtext{\frac{1}{2}} \mymathtext{\frac{1}{4}\correctanswer}
\end{document}

The code works as follow: first define a \correctanswer which expands to an empty string, and second emphasize (by typesetting in bold) text that contains this macro.

I'm using xstring's \noexpandarg to prevent \correctanswer from being expanded too early, but that doesn't work when the argument text is already passed to another command, such as \ensuremath : Although Bar is typeset in bold, \frac{1}{4} is not.

How can I get \frac{1}{4} to be typeset in bold?

PS: I don't really understand how expansion works. I've read a number of posts on this site, but I still can't figure out a correct solution to this particular problem. I therefore haven't included the numerous unfruitful attempts that I made, hoping that someone could instead provide me with a clear explanation :)

share|improve this question
    
For those wondering why I'm using such a bizarre syntax: I'm trying to build my own mutiple-choice template, and my current code has a \choice command chich takes four arguments, with one (or more) containing \correctanswer, which allows me to use the same document for the test and the correction, by switching between \solutionstrue and \solutionsfalse. –  Clément Dec 31 '11 at 15:03
    
why not use the syntax \correctanswer{\mytext{Bar}}, defining it either as \newcommand{\correctanswer}[1]{#1} or \newcommand{\correctanswer}[1]{\textbf{#1}} depending on \ifsolutions? Using xstring here seems like an overkill. –  Bruno Le Floch Dec 31 '11 at 21:50
    
@BrunoLeFloch: Salut Bruno. In my full example, I do more than making the text bold: there's a checkbox before every answer, which gets checked if \ifsolutions is true and the answer is the correct one. –  Clément Jan 2 '12 at 12:11
add comment

3 Answers

Just don't use \ensuremath: it adds a level of grouping that makes impossible for \IfSubStr to find \correctanswer; indeed the test

\IfSubStr{1{2}3}{2}{true}{false}

returns "false". So write

\newcommand{\mymathtext}[1]{\mytext{$#1$}}

Please, note that your code adds plenty of spurious spaces:

\newcommand{\mytext}[1]{%
    Text :
    \noexpandarg
    \IfSubStr{#1}{\correctanswer}{%
        \textbf{\boldmath #1}%
    }{%
        #1%
    }
}

I would rewrite it as

\newcommand{\mytext}[1]{%
    Text : % be sure we want a space
    \noexpandarg
    \IfSubStr{#1}{\correctanswer}
      {\textbf{\boldmath #1}}
      {#1}%
}

But probably the best thing is to define a *-variant:

\makeatletter
\newcommand{\mytext}{\@ifstar\mytext@s\mytext@n}
\newcommand{\mytext@s}[1]{\textbf{\boldmath #1}}
\newcommand{\mytext@n}[1]{#1}
\makeatother

and say \mytext{Yes} or \mytext*{No} (correct answer); for math just add $: \mytext{$\frac{1}{2}$} or \mytext*{$\frac{1}{4}$}

This is the standard way to define a command with a *-variant; since we need to use @ commands, the code must be enclosed between \makeatletter and \makeatother.

The command \mytext is defined to peek at what follows it with \@ifstar; if a * follows, we execute \mytext@s, otherwise \mytext@n, that we define next just normally: \mytext@s{x} does \textbf{\boldmath x}, while \mytext@n{x} does simply x. Indeed TeX will substitute \mytext* with \mytext@s, so it will next see the argument to pass to this command, and similarly without a *.

In order to arrange things with \ifsolution, you can say

\newif\ifsolution
\makeatletter
\newcommand{\mytext}{\@ifstar\mytext@s\mytext@n}
\newcommand{\mytext@s}[1]{%
  \begingroup
  \ifsolution\bfseries\boldmath\fi
  #1%
  \endgroup}
\newcommand{\mytext@s}[1]{#1}
\makeatletter

so that the \bfseries\boldmath commands will be issued only when \ifsolution is set to true.

Simpler version

A simpler definition might be:

\usepackage{xparse}
\newif\ifsolution

\NewDocumentCommand{\answer}{st{+}m}
  {\begingroup
   \ifsolution\IfBooleanT{#1}{\bfseries\boldmath}\fi
   \IfBooleanT{#2}{$}#3\IfBooleanT{#2}{$}%
   \endgroup}

\answer{Yes} \answer*{No}

\answer+{\frac{1}{2}} \answer*+{\frac{1}{4}}

\solutiontrue

\answer{Yes} \answer*{No}

\answer+{\frac{1}{2}} \answer*+{\frac{1}{4}}

You'll get

Yes No
1/2 1/4
Yes No
1/2 1/4

with the fractions in math mode, of course. The presence of + implies a formula, as you can see.

EDIT

Assuming that you have a \answerformat macro that formats answers, say

\newcommand{\answerformat}[1]{\mbox{\checkbox\qquad{#1}}\\}

(where \checkbox prints a box), you can use a syntax such as

\answers{Yes}*{No}+{\frac{1}{2}}+{\frac{1}{4}}

or even

\answers[3]{Yes}{No}*+{\frac{1}{2}}

that is, preceding the correct answer by * and math answers by +; the optional argument tells how many choices you have (default 4):

\usepackage{xparse}
\NewDocumentCommand{\answer}{st{+}m}
  {\answerformat{%
     \ifsolution\IfBooleanT{#1}{\bfseries\boldmath}\fi
     \IfBooleanT{#2}{$}#3\IfBooleanT{#2}{$}}
   \ifnum\value{anscount}<\answernumber
     \stepcounter{anscount}\expandafter\answer
   \fi}
\NewDocumentCommand{\answers}{O{4}}
  {\setcounter{anscount}{1}\chardef\answernumber=#1\relax
   \answer}
\newcounter{anscount}
share|improve this answer
    
Awesome answer. Just let me some time to make sure I fully understand it: I had never heard about *-variants before :) –  Clément Dec 31 '11 at 16:36
    
Probably the last version is the most flexible one (just don't ever write \answer+*). –  egreg Dec 31 '11 at 16:39
    
Can you explain how the @n and @s notations work (or point me to a relevant resource)? Thanks! –  Clément Dec 31 '11 at 16:40
    
Thanks for the explanation! –  Clément Jan 2 '12 at 23:58
add comment

I think you can also use xstring. Use the commands exploregroup and noexpandarg.

\documentclass{minimal}

\usepackage{xstring}

\newcommand{\correctanswer}{}
\newcommand{\mytext}[1]{
    Text :
    \noexpandarg
    \exploregroups
    \IfSubStr{#1}{\correctanswer}{
        \textbf{\boldmath #1}
    }{%
        #1
    }
}
\newcommand{\mymathtext}[1]{\mytext{\ensuremath{#1}}}

\begin{document}
    \mytext{Foo} \mytext{Bar\correctanswer} \mymathtext{\frac{1}{2}} \mymathtext{\frac{1}{4}\correctanswer}
\end{document}

enter image description here

share|improve this answer
    
Awesome, thanks! –  Clément Jan 2 '12 at 12:11
add comment
up vote 0 down vote accepted

After reading the relevant section in xstring's manual, I realize that using IfSubStr* works perfectly =)

share|improve this answer
    
It does; but one has to think whether adding a \correctanswer tag inside the argument is really a good solution. I don't think so. –  egreg Jan 2 '12 at 13:49
    
@egreg: Your solution is indeed very pretty; the only trouble that I have atm is that my real-life document has constructs like \choices{Choice 1}{Choice 2}{Choice 3}{Choice 4}, and the command \choices in turns calls \mytext four times, and \mytext adds a checkbox before every choice, and in solution mode checks the right box. I think that the ideal solution would be to pass to \choices a second argument (a number between 1 and 4), which would specify which answer is correct, but since I didn't know how to do that I thought I'd tag the correct answer with \correctanswer. –  Clément Jan 3 '12 at 0:02
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.