15

Given a control sequence \z that was defined like \let\z=z, how do you get the catcode the character z had at the time \z was defined?

The obvious solution

{\catcode`z=12 \global\let\z=z}
\the\catcode`\z

seems to work at the first glance, but it gives the wrong result 11 because '\z isn't interpreted as the previously defined control sequence but just another denotation of the character code of the letter z.

Using a different control sequence name makes it obvious

{\catcode`z=12 \global\let\thez=z}
\the\catcode`\thez

when it fails with

! Improper alphabetic constant.

This question deals with a similar problem, getting the character code of such a control sequence, but I don't see a way to use it for this problem as \meaning only returns characters of category 12 and 10.

12

An implicit character cannot be active, nor it can have catcode 0, 5, 9, 14 or 15. Check each possibility:

\def\catcodeofimplicitchar#1{%
  \ifcat\noexpand#1\bgroup 1\else
  \ifcat\noexpand#1\egroup 2\else
  \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#1112\else
  -1\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
}

\let\one={ \let\two=} \let\three=$
\let\four=& \let\six=# \let\seven=^
\let\eight=_ \let\eleven=z \let\twelve=0
\begingroup\def\\#1:{\global\let\ten= #1}\\ :\endgroup
\let\thirteen=~

{\tt\meaning\one}:
\catcodeofimplicitchar\one

{\tt\meaning\two}:
\catcodeofimplicitchar\two

{\tt\meaning\three}:
\catcodeofimplicitchar\three

{\tt\meaning\four}:
\catcodeofimplicitchar\four

{\tt\meaning\six}:
\catcodeofimplicitchar\six

{\tt\meaning\seven}:
\catcodeofimplicitchar\seven

{\tt\meaning\eight}:
\catcodeofimplicitchar\eight

{\tt\meaning\ten}:
\catcodeofimplicitchar\ten

{\tt\meaning\eleven}:
\catcodeofimplicitchar\eleven

{\tt\meaning\twelve}:
\catcodeofimplicitchar\twelve

{\tt\meaning\empty}:
\catcodeofimplicitchar\empty

\ifnum\catcodeofimplicitchar\one=1 GOOD\else BAD\fi

\bye

enter image description here

  • I chose this answer because it's more direct and easier to understand – siracusa Sep 28 '16 at 15:45
11

You do want the same general idea as in How to get character code defined with \let (! Improper alphabetic constant), but you need to use the text of the \meaning. An example which covers three cases (space, letter, other), and which extends naturally to the other cases:

\long\def\getcatcode#1{%
  \expandafter\getcatcodeaux\meaning#1\stop
}
\edef\getcatcodeaux#1\stop{%
  \noexpand\getcatcodespace#1{}{}\detokenize{blank space}\noexpand\stop
  \noexpand\getcatcodeletter#1{}{}\detokenize{the letter}\noexpand\stop
  \noexpand\getcatcodeother#1{}{}\detokenize{the character}\noexpand\stop
}
\edef\temp{%
  \def\noexpand\getcatcodespace##1\detokenize{blank space}##2\noexpand\stop{%
    \noexpand\ifx\relax##1\relax
      10%
    \noexpand\fi
  }%
  \def\noexpand\getcatcodeletter##1\detokenize{the letter}##2\noexpand\stop{%
    \noexpand\ifx\relax##1\relax
      11%
    \noexpand\fi
  }%
  \def\noexpand\getcatcodeother##1\detokenize{the character}##2\noexpand\stop{%
    \noexpand\ifx\relax##1\relax
      12%
    \noexpand\fi
  }%
}
\temp

This is all expandable so it can go into the argument of \catcode or similar. I've not added any defensive code in case \z here is a macro which might contain the test string, a chardef, etc., but one can extend the idea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.