How to check if the value of a parameter is a number?
Update:
Since it appears that the \IfInteger
from the xtring
package perceives blank strings as integers (the empty string {}
is ok, but not { }
), I have defined a modified macro \IsInteger
which handles that case:
\documentclass{article}
\newcommand*{\IsInteger}[3]{%
\IfStrEq{#1}{ }{%
#3% is a blank string
}{%
\IfInteger{#1}{#2}{#3}%
}%
}%
\usepackage{xstring}
\begin{document}
$2$ is \IsInteger{2}{an integer}{not an integer}\par
$2.0$ is \IsInteger{2.0}{an integer}{not an integer}
$-7$ is \IsInteger{-7}{an integer}{not an integer}\par
$-7.0$ is \IsInteger{-7.0}{an integer}{not an integer}
$2.1$ is \IsInteger{2.1}{an integer}{not an integer}\par
$-7.1$ is \IsInteger{-7.1}{an integer}{not an integer}
a is \IsInteger{a}{an integer}{not an integer}
Empty String is \IsInteger{}{an integer}{not an integer}\par
Blank String is \IsInteger{ }{an integer}{not an integer}
\end{document}
You can use IfInteger
from the xstring
package to test if it is an integer number:
There is also \IfDecimal
which works similarly.
\documentclass{article}
\usepackage{xstring}
\begin{document}
2 is \IfInteger{2}{integer}{not an integer}
a is \IfInteger{a}{integer}{not an integer}
\end{document}
It depends mostly on the expected input and also on the context where you want to use the command.
If your expected input is either a number or something that doesn't start with digits, then
\newcommand{\mycommand}[1]{%
\ifnum0<0#1\relax
#1 is a positive number%
\else
#1 is not a positive number%
\fi}
will do. For example, \mycommand{42}
will do the comparison 0<042
which is true; instead, with \mycommand{*}
TeX will see \ifnum0<0*\relax
and it will test 0<0
, which is false, so the *
will be ignored as part of the "true text". Also the test from \mycommand{0}
will evaluate to false.
On the other hand, with \mycommand{1x}
the test will evaluate to true and give wrong results.
Another expandable way can be
\def\mycommand#1{%
\if\relax\detokenize\expandafter{\romannumeral-0#1}\relax
#1 is a number%
\else
#1 is not a number%
\fi
}
but \mycommand{0}
would test true. Here \mycommand{1x}
would answer that 1x
is not a number.
However, the argument should not contain "dangerous" items: \mycommand{\textbf{x}}
would fail miserably.
A non-expandable test can be
\makeatletter
\def\mycommand#1{%
\afterassignment\get@args\count@=0#1\hfuzz#1\hfuzz}
\def\get@args#1\hfuzz#2\hfuzz{%
\if\relax\detokenize{#1}\relax
#2 is a number%
\else
#2 is not a number%
\fi
}
\makeatother
This works also with input such as \mycommand{\textbf{1}}
(the test will evaluate to false).
Here is an expandable solution that accepts even undefined control sequences. It is admittedly acrobatic.
Some of the commands in catoptions package are redefined here for the sake of speed and experimentation.
\documentclass[a4paper]{article}
\usepackage{catoptions}
\makeatletter
\new@def\cptifdef#1{%
\cptifblank{#1}{%
\@secondoftwo
}{%
\csname @\ifx#1\@undefined second\else
\ifx#1\relax second\else first\fi\fi oftwo\endcsname
}%
}
\new@def\cptifundef#1{\cptifdef{#1}\@secondoftwo\@firstoftwo}
\new@def\cptifleftbraced#1{%
\cptifblank{#1}{%
\@secondoftwo
}{%
\csname @\if\expandafter\cpt@car\detokenize{#1}\car@nil
\expandafter\cpt@car\string{\car@nil\ifnum0=`}\fi
first\else second\fi oftwo\endcsname
}%
}
\new@def\cptifxpandable#1{%
\cptifleftbraced{#1}{%
\@secondoftwo
}{%
\expandafter\ifx\noexpand#1#1%
\expandafter\@secondoftwo
\else
\expandafter\@firstoftwo
\fi
}%
}
\newcommand\cpttwooftwo[2]{#1#2}
\newcommand\cptifblank[1]{%
\expandafter\ifx\expandafter\noboundary\@gobble#1.\noboundary
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\newcommand\cptifcmdeq[2]{%
\ifx#1#2\cpt@quark
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\long\def\cptifsolo#1{%
\if0\pdfstrcmp{\detokenize\expandafter
{\cpttwooftwo#1{}{}}}{\detokenize{#1{}}}%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\new@def\cptxpand#1{%
\romannumeral-`\q\cptifblank{#1}{\space}{\cpt@xpand#1\xpand}%
}
\def\cpt@xpand#1#2\xpand{%
\cptifsolo{#1}{%
\cptifundef{#1}{%
\cpt@@xpand{#2}{\noexpand#1}%
}{%
\cptifxpandable{#1}{%
\cpt@@xpand{#2}{\expandafter\cpt@xpand#1\xpand}%
}{%
\cpt@@xpand{#2}{\noexpand#1}%
}%
}%
}{%
\cpt@@xpand{#2}{\cpt@xpand#1\xpand}%
}%
}
\def\cpt@@xpand#1{%
\expandafter\cptswap\expandafter{\romannumeral-`\q
\cptifblank{#1}{\space}{\cpt@xpand#1\xpand}}%
}
\def\ifinteger#1{%
\if\cptifblank{#1}{1}{\expandafter\ifinteger@a\romannumeral-`\q
\cpt@xpand#1\xpand\cpt@nnil}00%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\def\ifinteger@a#1{%
\cptifcmdeq#1\cpt@nnil{}{%
\ifinteger@b#1\cpt@nil0123456789\cpt@nnil
}%
}
\def\ifinteger@b#1\cpt@nil#2#3\cpt@nnil{%
\expandafter\cptifcmdeq\cpt@car#1\car@nil#2{%
\ifinteger@a
}{%
\cptifblank{#3}{%
1\cpt@removetonnil
}{%
\ifinteger@b#1\cpt@nil#3\cpt@nnil
}%
}%
}
% Tests
\def\cmda{01}
\def\cmdb{xy}
\let\cmdc\undefined
\edef\cmdd{\ifinteger{\cmda}{True}{False}}
\edef\cmde{\ifinteger{\cmdc}{True}{False}}
\edef\cmdf{\ifinteger{\cmda\cmdb\cmdc}{True}{False}}
\show\cmdf