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.
a
is 11 (letter) not 10 (space).