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.

Let's say I have some macro (\iPrint in the MWE) that internally uses active characters to interpret its argument:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\begingroup
  \lccode`\~=`\|
  \lowercase{\endgroup
    \def~#1~{\textbf{#1}}%
  }
\def\iPrint{%
  \begingroup
  \catcode`\|=\active
  \iPrintX
}
\def\iPrintX#1{%
  #1
  \endgroup
}

\begin{document}
\def\temp{This |doesn't work|, though :-(}
\begin{itemize}
  \item \iPrint{This |works pretty| well!}
  \item \iPrint{\temp}
\end{itemize}
\end{document}

This yields:

Output

AFAIU the issue, catcodes are assigned at definition time of a macro: When \temp is defined, | is not active. However, is there something I can do within \iPrint to make it active anyway? Some sort of recoding the argument with the current catcodes?

share|improve this question

2 Answers 2

up vote 11 down vote accepted

When you say

\def\temp{This |doesn't work|, though :-(}

the catcode of | is fixed and setting \catcode`|=\active has no effect when the expansion of \temp is performed: the | characters in the replacement text have category code 12.

One can use \scantokens to reassign category codes, but the macros must be expanded before \scantokens comes into play:

\makeatletter
\begingroup
  \lccode`\~=`\|
  \lowercase{\endgroup
    \def~#1~{\textbf{#1}}%
  }
\def\iPrint#1{%
  \begingroup
  \catcode`\|=\active
  \protected@edef\reserved@iprint{\noexpand\scantokens{#1\noexpand\empty}}\reserved@iprint
  \endgroup
}
\makeatother

If the input to \iPrint is known to be only text or a macro (say \iPrint{\temp}), then the simpler

\def\iPrint#1{%
  \begingroup
  \catcode`\|=\active
  \scantokens\expandafter{#1\empty}%
  \endgroup}

would work. If the argument is more complicated (text and macros), then the more complicated approach with \protected@edef appears to be necessary; it will expand all macros, but won't go too much deeply with "protected" macros.

The \empty at the end of the argument to \scantokens is customary to avoid a spurious space: \scantokens actually emulates the input of a file and all files are implicitly terminated with an empty line. Inside \protected@edef it mustn't be expanded, so we add \noexpand in front of it.

(Thanks to Bruno Le Floch for correcting an inaccuracy.)

share|improve this answer
1  
Your last paragraph is inaccurate. The \noexpand at the end of the argument to \scantokens can be replaced by \relax, or by \empty. It's only effect is that the last line of the virtual file built by \scantokens ends with a control word, hence a newline doesn't produce a space. As it is, your \noexpand acts on \endgroup, which luckily does nothing bad. –  Bruno Le Floch Jan 29 '12 at 0:10

Catcodes are assigned when a input character is read. TeX then looks up the current value for this input and attaches the catcode. Later it can not be changed. So you must reread the input if you want to change it. E.g. by writing it to a file and then reinput this file. Or by using \scantokens.

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\begingroup
  \lccode`\~=`\|
  \lowercase{\endgroup
    \def~#1~{\textbf{#1}}%
  }
\def\iPrint{%
  \begingroup
  \catcode`\|=\active
  \iPrintX
}
\def\iPrintX#1{%
  #1
  \endgroup
}

\begin{document}
\def\temp{This |doesn't work|, though :-(\relax}
\begin{itemize}
  \item \iPrint{This |works pretty| well!}
  \item \iPrint{\scantokens\expandafter{\temp}}.
  \item \iPrint{\temp}.
\end{itemize}
\end{document}
share|improve this answer
    
Thanks! However, I was looking for a way to do it on the callee side, which is what egreg's solution provides. –  Daniel Jan 28 '12 at 17:34

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.