Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

How do I test if a given parameter is a number, in order to apply a different style? And if not, just ignore... Like:

\domorestuffifnumber{things} -> things
\domorestuffifnumber{123}    -> \emph{123}

Thanks.

share|improve this question
8  
You accepted my answer pretty quickly. That might discourage others from providing better answers. It'd probably be best to wait a day (or at least several hours) before accepting an answer. –  TH. Dec 15 '10 at 23:57
    
I have a number testing code in my tikz-timing package. See the source code if you are interested. –  Martin Scharrer May 21 '12 at 7:30

5 Answers 5

up vote 18 down vote accepted

Here's a slightly flawed, but slightly more generic thing than you're asking for.

\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand\ifnumber[1]{%
        \begingroup
        \edef\temp{#1}%
        \expandafter\ifstrempty\expandafter{\temp}
                {\endgroup\@secondoftwo}
                {\expandafter\ifnumber@i\temp\@nnil}%
}
\def\ifnumber@i#1#2\@nnil{%
        \if-#1%
                \ifstrempty{#2}
                        {\def\temp{X}}
                        {\def\temp{#2}}%
        \else
                \def\temp{#1#2}%
        \fi
        \afterassignment\ifnumhelper
        \count@0\temp\relax\@nnil
        \endgroup
}

\def\numrelax{\relax}%
\def\ifnumhelper#1\@nnil{%
        \def\temp{#1}%
        \ifx\temp\numrelax
                \aftergroup\@firstoftwo
        \else
                \aftergroup\@secondoftwo
        \fi
}
\makeatother

\newcommand\testnumber[1]{#1: \ifnumber{#1}{Number}{Not a number}\par}
\begin{document}
\def\foo{-55}
\testnumber{1234}
\testnumber{\foo}
\testnumber{-}
\testnumber{}
\testnumber{1}
\testnumber{1234abc}
\testnumber{abc1234}
\end{document}

It's slightly complicated by checking if the first token in the expansion of the argument is a -. Unfortunately, it does not work if the argument is a register. (It probably doesn't work in other cases too.)

But from the \ifnumber macro, you should easily be about to build what you want.

\newcommand\domorestuffifnumber[1]{\ifnumber{#1}{\emph{#1}}{#1}}
share|improve this answer
    
It may be a feature not to work if the argument is a register: with an argument of \count@ 0, we wouldn't want \count@ to be unpacked. In a situation where we want to get a number at any cost, then the only non-expandable control sequences which are allowed are registers, so we can test \ifcat\relax and throw in a \the to unpack. –  Bruno Le Floch May 2 '11 at 16:18
\documentclass{article}
\def\isnum#1{%
  \if!\ifnum9<1#1!\else_\fi
    \emph{#1}\else#1\fi}

\begin{document}

\isnum{dummy}
\isnum{123}

\end{document}

if #1 is a number we have \ifnum9<1xxx which s true and therefore empty which leads to \if!! which is also true and \emph{#1} is the output. In the other case we have (#1 mybe 0a) \ifnum9<10a which is true and leaves a. Therefore we compare \if!a which is wrong, the reason why now the else part the output is.

share|improve this answer
    
That's pretty clever but it doesn't handle negative numbers and like mine, doesn't handle registers. –  TH. Dec 15 '10 at 21:43
    
why the underscore after the first else? –  Yiannis Lazarides May 2 '11 at 15:27
    
@Yiannis: Ah, a copy and past error from another macro where I used it in another way. That part is never reached, you can use it without else_ or with any other text. –  Herbert May 2 '11 at 15:44
    
I thought so! Your construction would also work with ifcat rather than the if. Very clever. –  Yiannis Lazarides May 2 '11 at 17:27

A LuaTeX solution:

\documentclass{article}
\begin{document}

\directlua{ dofile("myluastuff.lua") }

\newcommand\domorestuffifnumber[1]{%
  \directlua{ 
    domorestuffifnumber("#1") 
}}

\def\foo{-55}
\domorestuffifnumber{1234}
\domorestuffifnumber{\foo}
\domorestuffifnumber{-}
\domorestuffifnumber{}
\domorestuffifnumber{1}
\domorestuffifnumber{1234abc}
\domorestuffifnumber{abc1234}
\end{document}

and the myluastuff.lua file:

function domorestuffifnumber( arg )
  if tonumber(arg) then 
    tex.sprint("\\emph{" .. arg .. "}") 
  else
    tex.sprint(arg or "")
 end
end

I think the solution is quite readable.

share|improve this answer

This is a somewhat late answer, but I am including it here for completeness. When TeX is expecting a number a trailing zero will be ignored if it is followed by another number. However, if the 0 is followed by a non-number it will stop the scanning and insert the letter in the stream. The macro that follows capitalizes on this fact. We set a counter this way within a box. If it is a number the input gets fully absorbed and the width of the box is zero. If it is not a number the box will contain the non-numbers and hence its width will be greater than zero. By testing for the width of the box we can know if the input was a number or not.

\documentclass{article}
\makeatletter
\def\add@zero#1{0#1}
\def\isNum#1{%
   \sbox\z@{\@tempcnta=0#1\relax}
   %\setbox0\hbox{\expandafter\@tempcnta\expandafter\add@zero\numtest\relax}
   \ifdim\wd0>\z@\relax\@latex@warning{Not a number!}\else is numeric\fi
}

\begin{document}
\isNum{13}

% Handles registers
\isNum{\the\@tempcnta}

%warning for not a number
\isNum{dummy}
\makeatother
\end{document}

Empty input is treated a zero, and this can be useful in many situations.

(Edit: simplified as per egreg's comments)

share|improve this answer
    
\sbox\z@{\@tempcnta=\number0#1\relax} is just as good and doesn't require \add@zero and \numtest. Moreover, using \sbox is safer if color might be involved. Of course this tests only for non negative numbers. –  egreg May 1 '11 at 21:59
    
@egreg Thanks, I guess it is simpler and I like the idea of the sbox; problem it will fail on \isNum{\the\@tmpcnta} although I guess it can be fixed by an appropriate number of \expandafters. –  Yiannis Lazarides May 1 '11 at 22:09
    
also yours fails on \@tempcnta because of the @ without \makeatletter. The \expandafter in your code is useless, because TeX expands tokens when looking for a number (which it does after finding \@tempcnta). Indeed also \number in my code is redundant. –  egreg May 1 '11 at 22:31
    
@egreg I corrected the \makeatletter, I had it correct on my compversion and copied wrongly in the post. I will have another look at your suggestions for which I thank you and edit the code later. –  Yiannis Lazarides May 1 '11 at 22:38

The xstring package provides two commands: \IfInteger and \IfDecimal. Each of them uses the syntax

\IfInteger{<value being tested>}{<result if true>}{<result if false>}

If you don't want to differentiate between integers and decimals, we could do

\documentclass{article}
\usepackage{xstring}

\newcommand{\DoStuff}[1]{\emph{#1}}

\newcommand{\IfNumber}[1]
{%
  \IfInteger{#1}
    {\DoStuff{#1}}
    {%
      \IfDecimal{#1}
        {\DoStuff{#1}}
        {#1}%
    }%
}

\begin{document}

\IfNumber{123}

\IfNumber{123.123}

\IfNumber{abc}

\end{document}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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