6

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 :)

3
  • 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. Commented Dec 31, 2011 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. Commented Dec 31, 2011 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. Commented Jan 2, 2012 at 12:11

3 Answers 3

6

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} 
3
  • Awesome answer. Just let me some time to make sure I fully understand it: I had never heard about *-variants before :) Commented Dec 31, 2011 at 16:36
  • Probably the last version is the most flexible one (just don't ever write \answer+*). Commented Dec 31, 2011 at 16:39
  • Can you explain how the @n and @s notations work (or point me to a relevant resource)? Thanks! Commented Dec 31, 2011 at 16:40
3

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

0
1

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

2
  • 1
    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. Commented Jan 2, 2012 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. Commented Jan 3, 2012 at 0:02

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.