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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In answering another question, I ran into some issues trying to use a combination of \def and \char. Consider the following example:

\documentclass{minimal}
\usepackage{etoolbox}
\usepackage{xstring}
\makeatletter
\def\title@A{a A}
\def\title@B{b B}

\def\gettitle#1{
  \IfInteger{#1}{%
    \def\@tmp{\char#1}%
    \ifcsundef{title@\@tmp}{\@tmp}{\csname title@\@tmp\endcsname}%
  }{%
    \ifcsundef{title@#1}{#1}{\csname title@#1\endcsname}%
  }
}
\begin{document}
\gettitle{65}  \gettitle{A}

\gettitle{66}  \gettitle{B}

\gettitle{67}  \gettitle{C}
\end{document}

Output:

A a A

B b B

C C

It seems like \@tmp does not expand to be a single character, but instead expand to \char 65, which then doesn't work in \csname ... \endcsname. I thought that using \edef\@tmp{\char#1} would work, but it seems like \char is one of those functions that does not get expanded.

So in the end, is it possible to have \@tmp expand to A and not \char 65?

share|improve this question
up vote 10 down vote accepted

This can be done via the \lowercase trick:

\documentclass{minimal}
\usepackage{etoolbox}
\usepackage{xstring}
\makeatletter

\begingroup
  \catcode0=12 %
  \gdef\chrdef#1#2{%
    \begingroup
      \lccode0=\numexpr(#2)\relax
    \lowercase{\endgroup
      \def#1{^^@}%
    }%
  }%
\endgroup

\def\title@A{a A}
\def\title@B{b B}

\def\gettitle#1{
  \IfInteger{#1}{%
    \chrdef\@tmp{#1}%
    \ifcsundef{title@\@tmp}{\@tmp}{\csname title@\@tmp\endcsname}%
  }{%
    \ifcsundef{title@#1}{#1}{\csname title@#1\endcsname}%
  }
}
\begin{document}
\gettitle{65}  \gettitle{A}

\gettitle{66}  \gettitle{B}

\gettitle{67}  \gettitle{C}
\end{document}

Result

\lowercase (a not expandable command) converts the argument character token to its lower case character. This is configured by \lccode. The only exception is zero. If the \lccode is zero for a character, then the character remains unchanged. Therefore the example uses the character with code zero, which can be expressed as ^^@ in TeX notation. However, this character has usually the category code of invalid, there it is changed to 12 (other) in the outside group. Since the changes to \lccode should be reverted afterwards, the macro also uses a group.

share|improve this answer
    
Could you please give an explanation (or link to explanation) of what this \lowercase trick does? – JP-Ellis Feb 27 at 7:33
1  

The \char primitive isn't expandable. In XeTeX and LuaTeX we have \Uchar, which is and so can generate any character. For pdfTeX, with only 256 possible outcomes, we can set up a look-up table. Something like

\catcode`\@=11 %
\ifdefined\Uchar
  \def\Xchar#1{%
    \detokenize\expandafter{\Uchar\numexpr #1\relax}%
  }
\else
  \catcode`\^^@=12 %
  \begingroup
    \gdef\Xchar#1{%
     \romannumeral-`\0\expandafter\Xchar@aux\expandafter{\numexpr #1\relax}%
    }
    \gdef\Xchar@aux#1{%
      \ifcsname Xchar@\romannumeral #1\endcsname
        \csname Xchar@\romannumeral #1\endcsname
      \else
        \errmessage{Character out of range}%
      \fi
    }
    \count@=-1 %
    \lccode`\X=`\X %
    \loop
      \advance\count@ by 1 %
      \ifnum\count@<256 %
      \lccode`\^^@ = \count@ %
      \lowercase{%
        \expandafter\gdef\csname Xchar@\romannumeral\count@\endcsname{^^@}%
      }
    \repeat
  \endgroup
\fi
\catcode`\@=12 %

provide \Xchar to do the job. A more sophisticated version of the same idea can be used to provide different category code characters, and is implemented as \char_generate:nn in expl3. (The above is expandable at point-of-use as the lookup table is generated in advance.)

share|improve this answer
    
I'll have to analyse this answer some more to understand it... but since you mention \char_generate:nn, does that mean that there is a nice(r) LaTeX3 way of doing expanding \def\@tmp{\char#1}? – JP-Ellis Feb 27 at 8:11

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.