Simpler way to verify user input?

Microsoft Windows xp professional w/serv...
December 16, 2009 at 11:40:26
Specs: Windows XP
In my batch file program, I get the user input for drive speed. Something like this:

set /p WriteSpeed=Select write speed. (Max), 32x, 16x, 8x, 4x, 2x, 1x:

Then I need to verify that the user's input matches the allowed write speeds. My brute force method is to do this:

If /i "%WriteSpeed:~0,3%"=="MAX" goto :CONTINUE
If /i "%WriteSpeed:~0,2%"=="32" goto :CONTINUE
If /i "%WriteSpeed:~0,2%"=="16" goto :CONTINUE
If /i "%WriteSpeed:~0,1%"=="8" goto :CONTINUE
If /i "%WriteSpeed:~0,1%"=="4" goto :CONTINUE
If /i "%WriteSpeed:~0,1%"=="2" goto :CONTINUE
If /i "%WriteSpeed:~0,1%"=="1" goto :CONTINUE
goto :ERROR
:CONTINUE

Is there a simpler way to verify that the user's input is valid by using a FOR loop? I suspect not since I'm checking the first 3, 2 or 1 char(s) entered but I thought I'd ask just in case there is.

Thanks,
Sky

PS: The set /p statement might change per another thread but that's a different subject. :)


See More: Simpler way to verify user input?

Report •


#1
December 16, 2009 at 12:17:44
I would do this :

if not "%WriteSpeed%"=="MAX" if not "%WriteSpeed%"=="32" if not "%WriteSpeed%"=="16" if not "%WriteSpeed%"=="8" if not "%WriteSpeed%"=="4" if not "%WriteSpeed%"=="2" if not "%WriteSpeed%"=="1" goto error

goto continue

:continue
echo OK
goto end

:error
echo error
goto end

:end


You may need "IF /I" to check on mixed or lower case for "MAX".

Note that this solution checks for the exact content, while in your code, "322" may result in buggy behaviour.


Report •

#2
December 16, 2009 at 12:42:59
@echo off & setLocal EnableDELAYedExpansion
set /p c=16 2 or 4
goto :!c! 2> nul

:4
:2
:16
echo OK


=====================================
Helping others achieve escape felicity

M2


Report •

#3
December 16, 2009 at 13:55:49
set local enabedelayedexpansion
set valid=:1:2:4:8:16:
set yy=%valid%
set /p xx=speed:
set xx=:!xx!:
set valid=!valid:%xx%=!
if /i "!xx!" neq "max" (
if "%valid%" equ "%yy%" echo invalid
)

i like M2's version. I tried that the other day
(goto !var! 2>nul)
but i did something wrong and so it kicked the error.
now it works!


Report •

Related Solutions

#4
December 16, 2009 at 15:37:38
Hi tvc, m2 and nbrane,

You people come up with great code! One thing though, in my code I'm checking only for the "essential" values to give the user maximum flexibility. IOW, the user can type 16 or 16x for the speed and my code will accept either input as being valid. I think all of your code would reject user input which includes the "x" wouldn't they?

tvc,
I understand your code and I think I could include the appropriate ":~0,n" (where n=3, 2 or 1) after WriteSpeed to make it accept user input that did not include the trailing "x". Nicer than my code since it eliminates all of the repetitious "goto :CONTINUE" statements.

----------
Mechanix2Go said:
@echo off & setLocal EnableDELAYedExpansion
set /p c=16 2 or 4
goto :!c! 2> nul

:4
:2
:16
echo OK
----------
I don't understand how the "goto :!c! 2> nul" works. I do understand that the ":!c!" is a label formed by the user's input. I don't understand how the "2> nul" works. Could you explain to this dummy how it works?


----------
nbrane said:
set local enabedelayedexpansion
set valid=:1:2:4:8:16:
set yy=%valid%
set /p xx=speed:
set xx=:!xx!:
set valid=!valid:%xx%=!
if /i "!xx!" neq "max" (
if "%valid%" equ "%yy%" echo invalid
)
----------
I like learning a new (your) technique. I don't understand it yet and will have to do more learning about how the ":1:2:4:8:16:" works. I also don't understand why in the ":!xx!:" the colons are needed. I think the "!" are needed since the "set local enabedelayedexpansion" statement is used but I need to research that also.

Thanks much people!
Sky (who's just scratching the surface of batch file programming)


Report •

#5
December 16, 2009 at 16:45:27
2> nul supresses errors

Did you give up on your other thread?


=====================================
Helping others achieve escape felicity

M2


Report •

#6
December 16, 2009 at 18:52:58
-------------------------
Mechanix2Go said:
2> nul supresses errors
-------------------------

I see now that 2> is an accepted redirection command.

I like your code a lot. I modified it for testing as follows:

@echo off & setLocal EnableDELAYedExpansion

:LOOP
cls
echo.
set /p c=Enter 16 2 or 4: 
goto :!c! 2> nul
echo Invalid input %c%
pause
goto :LOOP

:4
:2
:16
echo OK
pause
goto :LOOP

If the user enters a valid input (16 2 or 4), it all works fine. But if
the user enters an invalid character like 9, the batch file is closed and
it never displays the "Invalid input %c%" line. Apparently a "goto :label"
command with an invalid label crashes cmd.

EDIT: Opps, I forgot that this code will not work if the user types 16x or 2x or 4x. It will only work with exact inputs of 16, 2, or 4.


-------------------------
Mechanix2Go said:
Did you give up on your other thread?
-------------------------

If you're referring to my "How to change SET /P statements on the fly?"
thread, I decided to go with tvc's solution of:

set /p WriteSpeed=Enter write speed: MAX, 32X, 16X, 8X, 4X, 2X, 1X (Default
is %WriteSpeed%):

Regarding cmd hanging with your attrib command, I have to run SFC yet and
then try again.

Thanks!
Sky

(Darn it! Why are the ads on the right overlapping and hiding the forum
window? I can't read the right end of long lines.)
OK, this forum doesn't like long text lines pasted from Notepad++.


Report •

#7
December 16, 2009 at 20:03:12
A not-found label doesn't crash cmd; it's just not found.

When you get around to sorting out your system we can determine if you really HAVE choice and where it is. That was the point of using attrib; and still is. In case you forgot.


=====================================
Helping others achieve escape felicity

M2


Report •

#8
December 16, 2009 at 23:55:12
-------------------------
Mechanix2Go said:

A not-found label doesn't crash cmd; it's just not found.

When you get around to sorting out your system we can determine if you really HAVE choice and where it is. That was the point of using attrib; and still is. In case you forgot.
-------------------------

M2,

No errors found on the system drive. Ran SFC /scannow and no errors reported there either.

I have a dual boot system with Boot-2 running a pristine copy of WinXP Pro. I ran this batch file in Boot-2:

@echo off
echo Got here 1.
pause

goto :9

echo Got here 2.
pause

Note that there is no label ":9" in the batch file so the goto has no where to go. Result is the first echo is displayed and pauses. When I press any key, the batch file closes exactly the same way as it does in Boot-1 running WinXP Pro.

Then I ran that batch file on my laptop running Vista. Same thing. Cmd closes when after the first echo is displayed.

I don't think my system is corrupt since the same thing happens in two WinXP Pro systems and one Vista system on a different computer. Running a goto with a not-found label closes the batch file in all three.

Sky


Report •

#9
December 17, 2009 at 01:09:46
this might handle the error (goto is apparently treated as
a different item than call, CALL is a fully independant CMD invocation, i think thats why my attempt didnt
work the other day...)

:top
set /p var=what ya want 1 2 3?
call !var! 2>nul
if %errorlevel% gtr 0 (
if "!var!" equ "" goto :bybye
echo invalid choice!
goto :top)
:1
echo one: check!
goto :ex
:2
echo ok for number two,
goto :ex
:3
echo three is cool...

:ex
your choice is logged...
goto :exx

:bybye
echo goodbye
:exx


Report •

#10
December 17, 2009 at 02:37:24
-------------------------
nbrane said:

this might handle the error (goto is apparently treated as
a different item than call, CALL is a fully independant CMD invocation, i think thats why my attempt didnt
work the other day...) .....snip.....
-------------------------

nbrane,

Good call! (pun intended).... ;o)
Using "call" instead of "goto" works without quitting cmd.

Since using call goes to another level, I think it would be necessary to "return" to the calling routine to avoid endless levels.

Here's a routine that is tested and works:

@echo off & setLocal EnableDELAYedExpansion

:LOOP
:: Set default value
set c=16

cls
echo.
set /p c=Enter 16 2 or 4: 
set ReturnVal=1
call :!c:~! ReturnVal 2> nul
if %ReturnVal%==0 goto :CONTINUE
echo Invalid input %c%
pause
goto :LOOP

:: ===== SUBROUTINES =====
:4
:2
:16
echo Value of c is %c%
pause
set %1=0
goto :EOF
:: ===== END OF SUBROUTINES =====

:CONTINUE
echo.
echo Got to continue.
pause
goto :LOOP

I think this method combined from M2 and you is a nice way to do it.

One problem though is that it errors out if the user enters 16x or 2x or 4x. The user's input must be precise for it to work properly.

Thanks,
Sky


Report •

#11
December 17, 2009 at 08:41:52
Skyhawk,
Indeed, you are right to say that a user might also be trying input like "2x" (instead of "2" on itself). The issue then is just : what do you want your user to be able to input ? I usually would opt for as much flexibility as possible. So, if the user inputs "2x", it would be allowed as well. What I am doing in my code, is the opposite : I reject anything which is NOT allowed. But, to translate the additional request, it would be something like this:

if /I not "%WriteSpeed%"=="MAX" if not "%WriteSpeed%"=="32" if not "%WriteSpeed%"=="16" if not "%WriteSpeed%"=="8" if not "%WriteSpeed%"=="4" if not "%WriteSpeed%"=="2" if not "%WriteSpeed%"=="1" if /I not "%WriteSpeed%"=="32x" if /I not "%WriteSpeed%"=="16x" if /I not "%WriteSpeed%"=="8x" if /I not "%WriteSpeed%"=="4x" if /I not "%WriteSpeed%"=="2x" if /I not "%WriteSpeed%"=="1x"

Note that a user can enter "1x" or "1X" ... it's a different text string. Also note that I'm not sure on "if /I not", it may also be "if not /I"

The problem with substring (substracting X first characters from an entered input) is that it will be buggy, if the input has a variable length. Example; suppose I want to type 16, but I type 15 ... it may end up being recognized as 1. While, to me, it should be reported as error...


Report •

#12
December 17, 2009 at 08:46:40
> One problem though is that it errors out if the user enters
> 16x or 2x or 4x. The user's input must be precise for it to
> work properly.

if /I "%var1%"=="16x" set var1=16

Problem solved ...


Report •

#13
December 17, 2009 at 10:19:26
-------------------------
tvc said:
The problem with substring (substracting X first characters from an entered input) is that it will be buggy, if the input has a variable length. Example; suppose I want to type 16, but I type 15 ... it may end up being recognized as 1. While, to me, it should be reported as error...
-------------------------

Hi tvc,

I just tried entering 15 in my program and you are indeed right! The value ended up as 1x while the user intended 16x. GOOD CATCH. I will replace my code with yours.

Thanks!
Sky


Report •

#14
December 17, 2009 at 11:00:54
-------------------------
Skyhawk said:
> One problem though is that it errors out if the user enters
> 16x or 2x or 4x. The user's input must be precise for it to
> work properly.

tvc said:
if /I "%var1%"=="16x" set var1=16
Problem solved ...
-------------------------

Hi tvc,

Here's the sample code implementing your suggestion. It works fine. One advantage of this code is that it rejects invalid input like 15.

@echo off & setLocal EnableDELAYedExpansion
:LOOP
:: Set default value
set c=MAX
cls
echo.
set /p c=Enter MAX,32,16,8,4,2,or 1 (Default=%c%): 
If /i "%c%"=="32x" set c=32
If /i "%c%"=="16x" set c=16
If /i "%c%"=="8x" set c=8
If /i "%c%"=="4x" set c=4
If /i "%c%"=="2x" set c=2
If /i "%c%"=="1x" set c=1
set ReturnVal=1
call :!c:~! ReturnVal 2> nul
if %ReturnVal%==0 goto :CONTINUE
echo Invalid input %c%
pause
goto :LOOP

:: ===== SUBROUTINES =====
:MAX
:32
:16
:8
:4
:2
:1
echo.
echo Valid input. Value of c is %c%
pause
set %1=0
goto :EOF
:: ===== END OF SUBROUTINES =====

:CONTINUE
echo.
echo Got to continue.
pause
goto :LOOP

Note that this code implements your other suggestion about how to show the default value in the prompt. :o)

I'm evaluating whether to use this method or your method in response #11 above.

Thanks for your input!
Sky


Report •

#15
December 17, 2009 at 11:06:13
Since this and the other thread are nominally about the same thing and since both are a mess. I recommend you start a new thread.

I'll post the script to create CHOICE.EXE just after this, so it doesn't clutter up the new thread.


=====================================
Helping others achieve escape felicity

M2


Report •

#16
December 17, 2009 at 12:38:58
Here's the code that I have settled on. It's tvc's code.

I'm taking back my desire to allow the user to add the "x" to his/her input. With tvc's code to allow that, the WriteSpeed can end up as 8 or 8x. So I'm going to force the user to only enter numeric digits without the trailing "x" or MAX (any case), to keep the code as simple as possible. Anyway, after the user uses the program for a while, it will be faster for him/her to just enter the numbers.

Actually the WriteSpeed needs to be in the form 32x not just 32. So I added a statement to add an "x" to non-MAX inputs.

This version will not accept invalid inputs like 15 or 8z. It appears to be bug proof.

-------------------------
@echo off

:LOOP

:: Set default WriteSpeed
Set WriteSpeed=MAX

cls
echo.
set /p WriteSpeed=Enter write speed - MAX,32,16,8,4,2,or 1 (default=%WriteSpeed%):
if /I not "%WriteSpeed%"=="MAX" if not "%WriteSpeed%"=="32" if not "%WriteSpeed%"=="16" if not "%WriteSpeed%"=="8" if not "%WriteSpeed%"=="4" if not "%WriteSpeed%"=="2" if not "%WriteSpeed%"=="1" goto :ERROR

:CONTINUE
echo.
:: Following adds "x" to numeric inputs only.
if /i "%WriteSpeed%" NEQ "Max" set "WriteSpeed=%WriteSpeed%X"
echo Valid input. WriteSpeed is %WriteSpeed%
pause
goto :LOOP

:ERROR
:: If got here is invalid input.
echo.
echo ---INVALID INPUT %WriteSpeed% --- (don't add X)
pause
goto :LOOP
-------------------------

Any comments or suggestions to improve are welcome.
Thanks to all who contributed!
Sky


Report •

#17
December 17, 2009 at 12:57:47
Honestly, if it's THAT big of a deal, rework your interface.

:loop
set speed=
echo Select speed:
echo    A) MAX
echo    B) 32x
echo    C) 16x
echo    D) 8x
echo    E) 4x
echo    F) 2x
echo    G) 1x
echo.
set /p input=[A-G]: 

if /i "%input%"=="A" set speed=MAX
if /i "%input%"=="B" set speed=32
if /i "%input%"=="C" set speed=16
if /i "%input%"=="D" set speed=8
if /i "%input%"=="E" set speed=4
if /i "%input%"=="F" set speed=2
if /i "%input%"=="G" set speed=1
if not defined speed goto loop


Report •


Ask Question