O argumento é um número?

A própria análise lexical do TeX não oferece muito suporte ao programador de macro: enquanto os códigos de categoria distinguem letras (ou o que o TeX considera como letras) de todo o resto, não há suporte para a análise de números.

A solução simples é comparar caracteres numéricos com os caracteres do argumento, um por um, por uma sequência de testes diretos, e declarar que o argumento “não é um número” se algum caractere falhar em todas as comparações:

\ifx1#1
\else\ifx2#1
...
\else\ifx9#1
\else\isanumfalse
\fi\fi...\fi
que se poderia, então, usar em uma macro recursiva de cauda para engolir um argumento. Pode-se fazer um pouco melhor assumindo (com segurança) que os códigos de caracteres dos dígitos são consecutivos:
\ifnum`#1<`0 \isanumfalse
\else\ifnum`#1>`9 \isanumfalse
     \fi
\fi
novamente usado em recursão de cauda. No entanto, essas formas não são muito satisfatórias: fazer a recursão “corretamente” é problemático (ela tem a tendência de engolir espaços no argumento) e, de qualquer forma, o próprio TeX tem mecanismos para ler números, e seria bom usá-los.

O pacote cite, de Donald Arseneau, oferece o seguinte teste para um argumento que seja um número inteiro estritamente positivo:

\def\IsPositive#1{%
  TT\fi
  \ifcat_\ifnum0<0#1 _\else A\fi
}
que pode ser adaptado para um teste para um inteiro não negativo, assim:
\def\IsNonNegative{%
  \ifcat_\ifnum9<1#1 _\else A\fi
}
ou um teste para qualquer inteiro:
\def\gobbleminus#1{\ifx-#1\else#1\fi}
\def\IsInteger#1{%
  TT\fi
  \ifcat_\ifnum9<1\gobbleminus#1 _\else A\fi
}
mas isso certamente estende a técnica além do que seria razoável.

Se não nos importarmos com o sinal, podemos usar o TeX para remover o número todo (sinal e tudo) do fluxo de entrada e, em seguida, observar o que restou:

\def\testnum#1{\afterassignment\testresult\count255=0#1 \end}
\def\testresult#1\end{\ifx\end#1\end\isanumtrue\else\isanumfalse\fi}
(cuja técnica é devida a David Kastrup; o truque para evitar os erros observados em uma versão anterior desta resposta, foi sugerido por Andreas Matthias).

Em uma discussão posterior sobre o mesmo tópico, Michael Downes ofereceu:

\def\IsInteger#1{%
  TT\fi
  \begingroup \lccode`\-=`\0 \lccode`+=`\0
    \lccode`\1=`\0 \lccode`\2=`\0 \lccode`\3=`\0
    \lccode`\4=`\0 \lccode`\5=`\0 \lccode`\6=`\0
    \lccode`\7=`\0 \lccode`\8=`\0 \lccode`\9=`\0
  \lowercase{\endgroup
    \expandafter\ifx\expandafter\delimiter
    \romannumeral0\string#1}\delimiter
}
que conta com \romannumeral para produzir um resultado vazio se seu argumento for zero. É uma pena que essa técnica tenha a infeliz propriedade de aceitar expressões simples como ‘1+2-3’; isso poderia ser resolvido por uma construção inicial similar a \gobbleminus.

Todas as funções completas acima são projetadas para serem usadas em condicionais do TeX escritas “ynaturalmente” — por exemplo:

\if\IsInteger{}%
  %
\else
  %
\fi
O classe LaTeX memoir tem seu próprio comando interno, o \checkifinteger{num}, que ajusta o comando condicional \ifinteger se o argumento for um inteiro.

É claro que toda essa confusão seria (essencialmente) desnecessária se houvesse um meio simples de “pegar” erros do TeX. Imaginando um primitivo para pegar erros \ifnoerror, poderíamos escrever:

\def\IsInteger#1{%
  TT%
  \ifnoerror
    \tempcount=#1\relax
% carries on if no error
    \expandafter\iftrue
  \else
% here if there was an error
    \expandafter\iffalse
  \fi
}
usando, assim, o próprio código de análise de inteiros do TeX para fazer a verificação. É uma pena que tal mecanismo nunca tenha sido definido (talvez seja impossível programa-lo dentro do TeX!).
memoir.cls
memoir


Do you have any question? Ask on: latex.net.br - we love qood questions!