--- myst: html_meta: keywords: LaTeX, programmation, commandes, macros, argument numérique, nombre --- # Comment déterminer qu'un argument est un nombre entier ? L'analyse lexicale propre à TeX n'offre pas beaucoup d'aide au programmeur de commandes : alors que les codes de catégorie, ou *catcodes*, distinguent les lettres (ou, pour être exact, ce que TeX considère comme des lettres) de tout le reste, il n'y a pas d'aide pour l'analyse des nombres. ## Avec l'extension L'extension , de Christian Tellechea, est dédiée à des tests et opérations sur des chaînes de *tokens*. Sa commande `\IfInteger` permet de traiter preque intégralement le problème. La gestion des espaces pouvant poser difficultés, Peter Grill propose une commande qui corrige ce point. En voici un exemple :` ``` \documentclass{article} \usepackage{lmodern} % Caractères plus lisibles \pagestyle{empty} % N'affiche pas de numéro de page \usepackage{xstring} \newcommand*{\EstEntier}[3]{% \IfStrEq{#1}{ }{% #3% est une chaîne vide. }{% \IfInteger{#1}{#2}{#3}% }% }% \begin{document} $2$ est \EstEntier{2}{un entier}{autre chose qu'un entier}.\par $2.0$ est \EstEntier{2.0}{un entier}{autre chose qu'un entier}. \par $-7$ est \EstEntier{-7}{un entier}{autre chose qu'un entier}.\par $-7.0$ est \EstEntier{-7.0}{un entier}{autre chose qu'un entier}. \par $2.1$ est \EstEntier{2.1}{un entier}{autre chose qu'un entier}.\par $-7.1$ est \EstEntier{-7.1}{un entier}{autre chose qu'un entier}. \par a est \EstEntier{a}{un entier}{autre chose qu'un entier}. \par La chaîne vide est \EstEntier{}{un entier}{autre chose qu'un entier}.\par Une chaîne d'espace est \EstEntier{ }{un entier}{autre chose qu'un entier}. \end{document} ``` Plus largement, l'extension propose aussi une commande pour tester qu'un nombre est décimal avec la commande `\IfDecimal`. ## Avec les commandes de base :::{warning} Les solutions proposées ici sont plus anciennes et demandent une connaissance un peu plus poussée de TeX. ::: La solution la plus simple consiste à comparer les différents caractères numériques avec les caractères de l'argument, un par un, et à déclarer que l'argument "n'est pas un nombre" si un caractère échoue à toutes les comparaisons : ```{noedit} \ifx1#1 \else\ifx2#1 ... \else\ifx9#1 \else\isanumfalse \fi\fi...\fi ``` que l'on utiliserait ensuite dans une commande qui teste ensuite, par récurrence, le reste de la chaîne de l'argument. On pourrait faire un peu mieux en supposant (de manière assez sereine) que les codes de caractères des chiffres sont consécutifs : ```{noedit} \ifnum''#1<''0 \isanumfalse \else\ifnum''#1>''9 \isanumfalse \fi \fi ``` Une nouvelle fois, ce test s'imbriquerait dans un test par récurrence pour tester toute la chaine de caractères de l'argument. Toutefois, ces formes ne sont pas très satisfaisantes : - il est difficile d'obtenir une forme de récurrence "correcte" (elle a tendance à engloutir les espaces dans l'argument) ; - TeX même dispose de mécanismes pour lire les nombres, et il serait bon de les utiliser. L'extension , de Donald Arseneau, propose le test suivant pour vérifier qu'un argument est un entier strictement positif : ```{noedit} \def\EstPositif#1{% TT\fi \ifcat//\ifnum0<0#1 //\else A\fi } ``` Ce test peut être adapté en un test pour un entier non négatif : ```{noedit} \def\EstNonNegatif{% \ifcat//\ifnum9<1#1 //\else A\fi } ``` Plus généralement, il peut être adapté pour un test pour tout entier (mais cela développe la technique au-delà de ce qui est raisonnable) : ```{noedit} \def\SupprimeMoins#1{\ifx-#1\else#1\fi} \def\EstEntier#1{% TT\fi \ifcat//\ifnum9<1\SupprimeMoins#1 //\else A\fi } ``` Si nous ne nous soucions pas du signe, nous pouvons utiliser TeX pour supprimer le nombre entier (signe et tout) du flux d'entrée, puis regarder ce qui reste. Le code suivant a été proposé par David Kastrup (avec une astuce suggérée par Andreas Matthias) : ```{noedit} \def\testnum#1{\afterassignment\testresultat\count255=0#1 \end} \def\testresultat#1\end{\ifx\end#1\end\isanumtrue\else\isanumfalse\fi} ``` Dans un fil de discussion sur le même sujet, Michael Downes a proposé le code suivant. Il est basé sur le fait que `\romannumeral` produit un résultat vide si son argument est zéro. Malheureusement, cette technique a la fâcheuse propriété d'accepter des expressions simples comme `1+2-3` ; ceci pourrait être résolu par une construction initiale similaire à `\SupprimeMoins`. ```{noedit} \def\EstEntier#1{% TT\fi \begingroup \lccode''\-=''\0 \lccod+=''\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 } ``` Toutes les fonctions ci-dessus sont conçues pour être utilisées dans des tests conditionnels TeX écrits "naturellement", par exemple : ```{noedit} \if\EstEntier{⟨sujet ou test⟩}% ⟨traitement de l'entier⟩% \else ⟨traitement de ce qui n'est pas un entier⟩% \fi ``` La classe possède sa propre commande interne, `\checkifinteger{num}`, qui active la commande conditionnelle `\ifinteger` selon que l'argument est un entier ou pas. Bien sûr, toutes ses suggestions seraient peu intéressantes s'il existait un moyen simple pour capter les erreurs de TeX. En imaginant une primitive de capture d'erreur `\ifnoerror`, on pourrait écrire : ```{noedit} \def\EstEntier#1{% TT% \ifnoerror \tempcount=#1\relax % gestion s'il n'y a pas d'erreur \expandafter\iftrue \else % gestion s'il y a une erreur \expandafter\iffalse \fi } ``` On utiliserait ainsi le code d'analyse des nombres entiers propre à TeX pour effectuer la vérification. Il est dommage qu'un tel mécanisme n'ait jamais été défini (et peut-être est-il impossible de programmer dans TeX!). :::{sources} - [How to check if the value of a parameter is a number?](https://tex.stackexchange.com/questions/50111/how-to-check-if-the-value-of-a-parameter-is-a-number) - [Is the argument a number?](faquk:FAQ-isitanum) :::