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.

I want to define a macro that typesets its argument in typewriter font and allows for underscore characters in its argument. Within a group, I make _ active, I define \_ to be typeset as an underscore, and then I insert the text.

This approach works great outside the definition of my macro, but TeX complains about two Missing $ inserted if I attempt to pass some text containing underscore characters as argument to the macro in question. What's going on?

enter image description here

\documentclass{article}

\newcommand\allowsforunderscores[1]%
{%
    \begingroup
        \ttfamily
        \catcode`\_=\active                     
        \let\_\textunderscore%
        #1%
    \endgroup
}   

\begin{document}

%\allowsforunderscores{Bertrand_Russell}    % if uncommented, this generates an error

% However, the following compiles just fine.
{
    \ttfamily
    \catcode`\_=\active                     
    \let\_\textunderscore
    Bertrand_Russell%
}
\( 4_4 \) % sanity check

\end{document}
share|improve this question
    
The underscore is not active when you do the definition. –  egreg Nov 20 '13 at 18:41
    
@egreg Do you mean that the macro parses its the argument before making _ active? –  Jubobs Nov 20 '13 at 18:42
    
No; but TeX absorbs tokens and catcode assignments are permanent (unless \scantokens is used). –  egreg Nov 20 '13 at 19:00
    
related: tex.stackexchange.com/questions/125572/… –  Jubobs Nov 21 '13 at 20:23

3 Answers 3

up vote 5 down vote accepted

There are three errors in your strategy.

First error: \let\_=\textunderscore doesn't do anything to the active _.

Second error: even if you type \let_=\textunderscore this wouldn't work, because _ is not active at the moment the definition is performed, so the token _ still has category code 12 and \let_=\textunderscore will be illegal at macro call. Note that you can use \_ to mean the character code of the underscore in a context like

\catcode`\_=\active

but this doesn't mean you can use \let\_=... for giving a meaning to the active underscore.

Third error: you can't change the category code of tokens in an already absorbed argument unless you use \scantokens.

\documentclass{article}

\makeatletter
%% A macro used in both strategies
%% At definition time the token `_` must be active
\begingroup
\catcode`_=\active
\gdef\activate@us{%
  \let_\textunderscore
  \catcode`\_=\active
}
\endgroup
%%% Alternative definition of \activate@us not requiring \gdef
%\begingroup\lccode`\~=`\_
%\lowercase{\endgroup
%  \def\activate@us{\let~\textunderscore\catcode`\_=\active}}


% First strategy
\newcommand{\allowforunderscoresA}{%
  \begingroup
  \activate@us
  \@allowforunderscores
}
\newcommand{\@allowforunderscores}[1]{%
   \ttfamily
   #1%
    \endgroup
}   

% Second strategy
\newcommand{\allowforunderscoresB}[1]{%
  \begingroup\activate@us\ttfamily
  \scantokens{#1\endinput}%
  \endgroup
}
\makeatother

\begin{document}

X\allowforunderscoresA{Bertrand_Russell}X

X\allowforunderscoresB{Bertrand_Russell}X%
\footnote{\allowforunderscoresB{Bertrand_Russell}}

\end{document}

Note that the first macro cannot appear in the argument to another command, while \allowforunderscoresB can.

enter image description here

share|improve this answer
    
What does it mean when you say is not active? What is activation? –  Sigur Nov 20 '13 at 20:15
1  
@Sigur See chapter 7 of the TeXbook. Activation, here, means make a character active, i.e. assign it a a catcode of 13. An active character then behaves almost like any other control sequence. ~ is an active character by default. –  Jubobs Nov 20 '13 at 20:31
    
Thanks for pointing out my mistakes (I'm still in the process of absorbing the knowledge from chapters 7 and 8 of the TeXbook). I understand your first strategy, which is similar to Werner's now deleted answer, but I'll have to look up \scantokens to understand your second strategy. A short follow-up question: is \gdef required here, or could \def have been used instead? –  Jubobs Nov 20 '13 at 21:30
    
@Jubobs \gdef is required because the definition has to be given in a context where _ is active; using a group doesn't require knowing what its catcode is outside the group. There are other ways, I added one. –  egreg Nov 20 '13 at 21:32
    
Thanks again. I thought mine was a dumb question, but the answers I got turned out to be very instructive about the arcane workings of TeX. –  Jubobs Nov 20 '13 at 22:36

What is passed to the macro is not a sequence of characters but a sequence of tokens. Catcode changes have no effect in tokens, they only change the mapping that is used when generating tokens from characters. This is exactly why you can not use \verb in a macro argument.

Simplest solution is to use url package and \url{Bertrand_Russell} (which uses math mode rather than catcode changes to do its work, or you can re-tokenise the argument using \scantokens after changing the catcodes.

share|improve this answer
    
Thanks for the explanation, but isn't loading a whole package for such a simple thing a bit overkill? –  Jubobs Nov 20 '13 at 18:59
    
@Jubobs no. If you do it as well with less tex code than is in url.sty then you be doing well:-) –  David Carlisle Nov 20 '13 at 19:35

underscore

But \allowsforunderscores can not be used inside the argument of another macro. It can be used with no problem in some environments. Except those nasty ones which gather their contents (they are rare).

\documentclass{article}

\catcode`_ 13
\newcommand\allowsforunderscores
{%
    \bgroup
        \ttfamily
        \let_\textunderscore
        \catcode`\_=\active                
    \let\next=%
}%
\catcode`_ 8

\begin{document}\thispagestyle{empty}

\allowsforunderscores{Bertrand_Russell}  

Hello $H_{ij}$ 

\end{document}
share|improve this answer

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.