How to test whether next token on input stream is catcode 10

Why doesn't the following code work? From a failed, now fixed, SO answer of mine:

\documentclass{article}

\usepackage{expl3}
\ExplSyntaxOn
\newcommand\latinabbrev[1]{
\peek_meaning:NTF . {% Same as \@ifnextchar
#1\@}
{ \peek_charcode:NTF a {% Check whether next char has same catcode as \'a, i.e., is a letter
#1.\@ }
{#1.\@}}}
\ExplSyntaxOff

%Omit final dot from each def.
\def\cf{\latinabbrev{cf}}

\begin{document}
Knuth, \cf The TeXbook.
\end{document}


This code should check the next character to see if it is a dot (so the code shouldn't insert another dot, and it should space the coming dot as if it at the end of a sentence), or catcode 10 (then it should insert a dot and a space), or something else (then it should insert a dot).

Although the other two branches seem to work, the \peek_charcode:NTF never seems to take its true branch, e.g., in the \cf T case. Why not?

-
No need to put % at the end of lines between \ExplSyntaxOn and \ExplSyntaxOff. –  Bruno Le Floch Aug 8 '11 at 12:48
@Bruno - Right: I've made the style more idiomatic. The non-working expl3 code was adapted from non-working non-expl3 code. –  Charles Stewart Aug 24 '11 at 9:03
in the LaTeX3 kernel code, we tend to put much more space than what you did. For one-line groups, the opening and closing braces are on the same line. For multi-line groups, the opening and closing braces are on lines of their own. I'd put comments on the same line as the function (e.g., the \peek_meaning:NTF and \peek_catcode:NTF lines in Joseph's code). –  Bruno Le Floch Aug 24 '11 at 9:31

I think you want \peek_catcode:NTF here:

\documentclass{article}

\usepackage{expl3}
\ExplSyntaxOn
\newcommand \latinabbrev [1] {
\peek_meaning:NTF .
{ #1 \@ }
{
\peek_catcode:NTF a
{ #1 . \@ ~ }
{ #1 . \@ }
}
}
\ExplSyntaxOff

%Omit final dot from each def.
\def\cf{\latinabbrev{cf}}

\begin{document}
Knuth, \cf The TeXbook.
\end{document}


peek_charcode:NTF checks for character code, in your case looking for a letter 'a'. Remember that TeX will ignore spaces after \cf, you you can never see a space here!

-

Use \futurelet. It's a TeX primitive, and it's the only way to do this sort of thing. In fact, that's why it was introduced.

The LaTeX 3 stuff uses \futurelet under the hood, and to my way of thinking makes things more complicated and considerably slower.

If you understand this you can solve the problem yourself (except perhaps for the problem of getting a space token into the \test macro).

$tex This is TeX, Version 3.1415926 (TeX Live 2009) **\relax *\def\test{\message{\ifcat\tmp_YES\else NO\fi}} *\futurelet\tmp\test a NO *\futurelet\tmp\test _ YES! Missing$ inserted.

-
Start nesting these tests and you'll see how expl3 makes this far more simple. –  Will Robertson Aug 5 '10 at 0:43
TeX is not a suitable language for doing string processing, even with the LaTeX 3 front end. I've answered the question as asked. –  Jonathan Fine Aug 6 '10 at 12:37
not a suitable language - Well, but if parsing in Tex is ugly, it is also a solved problem, that more than a handful of people know how to do, and it is not inefficient. It's not a good language for it, but I don't think it should be treated with contempt. –  Charles Stewart Aug 9 '10 at 9:56
Not sure where the ! comes from after the YES message. Furthermore, \ifcat\tmp_ should be \ifcat\noexpand\tmp_. Otherwise you can run into all sorts of trouble with expansion. –  Bruno Le Floch Aug 8 '11 at 12:46