views:

6146

answers:

8

I'm experimenting with a DOS batch file to perform a simple operation which requires the user to enter a non-negative integer. I'm using simple batch-file techniques to get user input:

@ECHO OFF
SET /P UserInput=Please Enter a Number:

The user can enter any text they want here, so I would like to add some routine to make sure what the user entered was a valid number. That is... they entered at least one character, and every character is a number from 0 to 9. I'd like something I can feed the UserInput into. At the end of the routine would be like an if/then that would run different statements based on whether or not it was actually a valid number.

I've experimented with loops and substrings and such, but my knowledge and understanding is still slim... so any help would be appreciated.

I could build an executable, and I know there are nicer ways to do things than batch files, but at least for this task I'm trying to keep it simple by using a batch file.

+3  A: 

You're probably not doing this in a DOS batch file. Or at least, support for set /p is unheard of for me in DOS :-)

You could use substrings. In fact I have written a parser for a specific regular language that way once, but it's cumbersome. The easiest way would probably be to assign the contents of %userinput% to another variable, using set /a. If the result comes out as 0 you need to check whether the input itself was 0, otherwise you can conclude it was a non-number:

@echo off
setlocal enableextensions enabledelayedexpansion
set /p UserInput=Enter a number: 
set /a Test=UserInput
if !Test! EQU 0 (
  if !UserInput! EQU 0 (
    echo Number
  ) else (
    echo Not a number
  )
) else (
  echo Number
)

However, this works only for numbers in the range of Int32. If you just care for any number (possibly floating-point as well) then you need to resort to the loop-based approach of dissecting it.

NOTE: Updated to solve the space issues. However, there is still a problem lurking: Entering 123/5 yields "number", since set /a can evaluate this ...

Joey
this does not work if user input is like for example, 123dd. It says "Number". It should be "Not a number"
ghostdog74
+1  A: 

This is the same idea as that of Johannes.. SET /A sets a numeric value. If the input is not a number, it changes it to 0. That's what you can exploit here to do your check.

@ECHO OFF
SET /P UserInput=Please Enter a Number:
IF %UserInput% EQU 0 GOTO E_INVALIDINPUT

SET /A UserInputVal="%UserInput%"*1
IF %UserInputVal% GTR 0 ECHO UserInput "%UserInputVal%" is a number
IF %UserInputVal% EQU 0 ECHO UserInput "%UserInputVal%" is not a number
GOTO EOF

:E_INVALIDINPUT
ECHO Invalid user input

:EOF


As an alternative, you could always create a little javascript file and call it from your batchfile. With parseInt() you could force the input to be an integer, or you could roll your own function to test the input.

Writing the javascript is just as fast as the batchfile, but it's much more powerful. No IDE or compiler required; notepad will do. Runs on every windows box, just like your batchfiles. So why not make use of it?

You can even mix batchfiles and javascript. Example:

contents of sleep.js:

var SleepSecs=WScript.Arguments.Item(0);
WScript.Sleep(SleepSecs*1000)

contents of sleep.cmd:

cscript /nologo sleep.js %1

You can now call this from a batchfile to make your script sleep for 10 seconds. Something like that is difficult to do with just a plain batchfile.

sleep 10
Wouter van Nifterick
A batch sleep function: ping -w 1000 -n %1 1.2.3.4 > nul :D
Joey
if I enter 1c as user input for example, i get error --> Invalid number. Numeric constants are either decimal (17),hexadecimal (0x11), or octal (021).0 was unexpected at this time. Do you have the same problem?
ghostdog74
A: 

Thanks all. I was trying to make it harder for myself looking at loops and string manipulation. I used your tips on math evaluation and comparison. Here's what I finally came up with as my concept script:

:Top
@ECHO OFF
ECHO.
ECHO ---------------------------------------
SET /P UserInput=Please Enter a Number: 
ECHO.
ECHO UserInput = %UserInput%
ECHO.
SET /A Evaluated=UserInput
ECHO Math-Evaluated UserInput = %Evaluated%
if %Evaluated% EQU %UserInput% (
    ECHO Integer
    IF %UserInput% GTR 0 ( ECHO Positive )
    IF %UserInput% LSS 0 ( ECHO Negative )
    IF %UserInput% EQU 0 ( ECHO Zero )
    REM - Other Comparison operators for numbers
    REM - LEQ - Less Than or Equal To
    REM - GEQ - Greater Than or Equal To
    REM - NEQ - Not Equal To
) ELSE (
    REM - Non-numbers and decimal numbers get kicked out here
    ECHO Non-Integer
)

GOTO Top

This method catches all numbers and can detect whether it's positive, negative, or zero. Any decimal or string will be detected as non-integers. The only edge case I've found is a string with spaces. For example, the text "Number 1" will cause the script to crash/close when the user input is evaluated as math. But in my situation, this is fine. I don't want my script to go on with invalid input.

B2Ben
So what does the exclamation point do differently than the percent sign? I'm not familiar with that...
B2Ben
A: 

You might also like this one - it's short and easy. This one use the multiplication trick to set TestVal. Comparing TestVal against UserInput allows all numeric values to get through including zeroes, only non-numerics will trigger the else statement. You could aslo set ErrorLevel or other variables to indicate a failed entry

@ECHO OFF SET TestVal=0

SET /P UserInput=Please Enter a Number: SET /A TestVal="%UserInput%"*1

If %TestVal%==%UserInput% ( ECHO You entered the number %TestVal% ) else ECHO UserInput "%UserInput%" is not a number

GOTO EOF

:EOF

A: 

Hi Everyone,

In addition to the remark about the error that occures when spaces are part of the users input. You can use errorlevel errorlevel=9165. It can be used for the spaces in a string or for the error handling of 'no' input.

Kind Regards,

Egbert

A: 
:ASK
SET /P number= Choose a number [1 or 2]: 
IF %number% EQU 1 GOTO ONE
IF %number% NEQ 1 (
  IF %number% EQU 2 GOTO TWO
  IF %number% NEQ 2 (
    CLS
    ECHO You need to choose a NUMBER: 1 OR 2.
    ECHO.
    GOTO ASK
  )
)

It works fine to me. If he chooses numbers less or greater, strings, floating number etc, he wil receive a message ("You need to choose a NUMBER: 1 OR 2.") and the INPUT will be asked again.

Nerun
why do i need to choose only 1 or 2? can you do it to take in all consideration?
ghostdog74
A: 

you can reinvent the wheel and grow a few white hairs doing string validation in batch, or you can use vbscript

strInput = WScript.Arguments.Item(0)
If IsNumeric(strInput) Then
    WScript.Echo "1"
Else
    WScript.Echo "0"
End If

save it as checkdigit.vbs and in your batch

@echo off
for /F %%A in ('cscript //nologo checkdigit.vbs 100') do (
        echo %%A
        rem use if to check whether its 1 or 0 and carry on from here
)
ghostdog74
A: 

You can also use a quite simple trick:

echo %userinput%|findstr /r /c:"^[0-9][0-9]*$" >nul
if errorlevel 1 (echo not a number) else (echo number)

This uses findstr's regular expression matching capabilities. They aren't very impressive but useful at times.

Joey
how about negative integers?
@levis: Quoting from the question: »perform a simple operation which requires the user to enter a **non-negative** integer« (emphasis mine)
Joey