23

For debugging a complicated macro I would like to print out the catcode of a token. Optimally I would like to have a macro \getcatcode such that, for example, \getcatcode{a} would expand to 10. How can this be done?

I found lots of information about how to set/change catcodes, but nothing about how to read them.

jochen
  • 1,067

3 Answers3

26

Use \catcode together with \the to get the catcode of the token:

\the\catcode`a

Note: The ` turns the next character into its ASCII number which is required for \catcode.

As custom macro:

\newcommand{\getcatcode}[1]{\the\catcode`#1}

Special characters must be escaped with a backslash, e.g. % must be written as \%, # as \# etc. It doesn't hurt to write normal letters the same way, e.g. \getcatcode\a works as well.

Martin Scharrer
  • 262,582
17

As explained in an exercise of the TeXbook one can also write

\newcommand{\printcatcode}[1]{%
   \ifcase\catcode`#1\relax
      escape\or
      beginning of group\or
      end of group\or
      math shift\or
      tab\or
      end of line\or
      parameter\or
      superscript\or
      subscript\or
      ignored\or
      space\or
      letter\or
      otherchar\or
      active\or
      comment\or
      ignored\fi}

 The category code is `\printcatcode\%'

Just to point out that any of the "code tables" in TeX can be used to access the value (\catcode, \lccode, \uccode, \mathcode, \delcode, \sfcode).

egreg
  • 1,121,712
8

The solutions offered by Martin and egreg print the current catcode of a character. I understood the original question to be how one can print the catcode of a token, i.e., one that has already been scanned, possibly in the past, when different catcodes were in effect. Consider this:

\catcode`\@=11
\newcommand{\x}{@}
\catcode`\@=12
\newcommand{\y}{@}

\newcommand{\printcatcode}[1]{
  \def\aux##1{
     \message{The catcode of the ##1 in \noexpand#1 is \getcatcode{##1}.^^J}
  }
  \expandafter\aux#1
}

\printcatcode{\x}
\printcatcode{\y}

Clearly the @s stored in the macros \x and \y have two different catcodes. However, with Martin's macro, we get:

The catcode of the @ in \x  is 12.
The catcode of the @ in \y  is 12.

That is because Martin's macro prints the 'current' catcode of the character represented by the token, rather than the catcode actually stored in the token.

The following is a better solution:

\begingroup%
  % locally ensure that characters have their expected catcodes
  \catcode`\$=3%
  \catcode`\&=4%
  \catcode`\#=6%
  \catcode`\^=7%
  \catcode`\_=8%
  \catcode`\ =10%
  \catcode`\a=11%
  \catcode`\+=12%
  \catcode`\~=13%
  \gdef\getcatcode#1{%
    \ifcat\noexpand#1$3\else%
    \ifcat\noexpand#1&4\else%
    \ifcat\noexpand#1##6\else%
    \ifcat\noexpand#1^7\else%
    \ifcat\noexpand#1_8\else%
    \ifcat\noexpand#1 10\else%
    \ifcat\noexpand#1a11\else%
    \ifcat\noexpand#1+12\else%
    \ifcat\noexpand#1\noexpand~13\else%
    \ifcat\noexpand#1\relax16\else%
      unknown%
    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi%
  }
\endgroup

With this, we get the expected answer:

The catcode of the @ in \x  is 11.
The catcode of the @ in \y  is 12.

The code is a bit awkward and I wonder if there is a more elegant solution. I was unable to test for catcodes 0, 1, 2, 5, 9, 14, and 15, but I am not sure if such catcodes can actually occur after the input has been tokenized.