Controlla solo l'input numerico nel file batch


10

Nella riga di comando basata su Windows NT (principalmente per XP o versioni successive), c'è un modo per verificare se uno switch fornito è solo un numero? A seconda del numero, voglio che esegua il ciclo attraverso il codice x il numero di volte


1
Personalmente, preferisco il metodo in questa risposta per: Assicurarsi che l'utente abbia inserito un numero intero . Utilizzare il processore dei comandi per fare tutto ciò che funziona. Puoi semplificarlo a 2 x linee come soluzione minima: 1 set /a NO_LINES=%~1.; 2 if %NO_LINES% NEQ %~1 goto ABORT. Quando i due sono uguali - La variabile o il parametro è numerico .
sarà il

Risposte:


18

Modificato per correggere la regex secondo il commento di Debham . Si scopre che l'aggiunta di uno spazio prima della pipe dopo l'eco aggiunge uno spazio alla stringa di pipe, che era ciò che interrompeva in precedenza l'inizio / fine della linea. Il regex potrebbe essere ulteriormente migliorato scartando gli spazi bianchi all'inizio e alla fine.


C'è il findstrcomando. Può cercare file con espressioni regolari, proprio come grepin Linux. Può anche cercare input convogliati.

@echo off

set param=%1

echo %param%| findstr /r "^[1-9][0-9]*$">nul

if %errorlevel% equ 0 (
    echo Valid number
)

Spiegazione

Il parametro utilizzato è impostato nella paramvariabile. Tuttavia, non c'è nulla che ti fermi usando direttamente il parametro ( %1per il primo parametro).

findstrviene utilizzato per cercare /rregex nell'input convogliato con il flag.

Il modello:

  • ^ significa l'inizio della riga.

  • [0-9]significa una cifra. I *mezzi il precedenti ripetuto zero o più volte. Quindi [0-9][0-9]*significa una cifra, più zero o più cifre. In altre parole, almeno una cifra. I +una o più volte non sembra essere supportata da findstr. Si noti che [1-9]viene utilizzato per la prima cifra per non consentire gli zeri iniziali - vedere i commenti.

  • $ significa fine della linea.


Ora, un ciclo for in batch per x numero di volte ... se x non è un numero valido, il loop in realtà non viene eseguito affatto - viene semplicemente ignorato per la riga successiva. Quindi non è necessario verificare se l'ingresso è un numero valido!

@echo off

set param=%1

for /l %%a in (1,1,%param%) do (
    echo %%a
)

Il ciclo viene eseguito utilizzando for /l, dove (x,y,z)significa start at x, incrementa di yfino al zraggiungimento. E imposta %%asul numero / iterazione corrente.

Nota: questo in realtà fallisce se c'è uno zero iniziale, facendo sì che il processore dei comandi lo tratti come un numero ottale. Vedi la risposta di dbenham per una soluzione migliore.


Spiegazione eccellente! E facile da usare
Luke canadese

1
Come scritto, questa soluzione fallirà con un parametro come "this 1 fails"The FINDSTR dovrebbe fare una corrispondenza esatta. Non dovrebbe corrispondere a una parola.
dbenham,

@dbenham Grazie. Ho provato prima / fine della corrispondenza di riga prima, ma non è riuscito a causa dell'eco che passa uno spazio aggiuntivo. Riparato ora.
Bob,

@CanadianLuke Potresti dare un'occhiata alla modifica.
Bob,

Un valore 09o 010potrebbe causare problemi a causa della notazione ottale. Vedi la mia risposta per regex che non consente la notazione ottale.
dbenham,

8

Quanto segue funziona molto bene per me. SET /a param=%1+0restituisce sempre 0se %1è vuoto o non numerico. Altrimenti, fornisce il numero indicato.

SET /a param=%1+0
IF NOT %param%==0 ECHO Valid number

4
Questo fallirà se parametro = 0. Inoltre tratterà un parametro come "1 + 1" come un numero, che potrebbe causare problemi, a seconda dei requisiti.
dbenham,

7

Questo rileverà se il primo parametro è un numero naturale valido (numero intero non negativo).

@echo off
echo %1|findstr /xr "[1-9][0-9]* 0" >nul && (
  echo %1 is a valid number
) || (
  echo %1 is NOT a valid number
)

Se si desidera consentire le virgolette attorno al numero, quindi

@echo off
echo "%~1"|findstr /xr /c:\"[1-9][0-9]*\" /c:\"0\" >nul && (
  echo %~1 is a valid number
) || (
  echo %~1 is NOT a valid number
)

Nota: gli zeri iniziali non sono consentiti perché batch li tratta come ottali, quindi un valore come 09non è valido e 010ha un valore di 8.


3

Ispirato dalla risposta eccellente di Bob con le seguenti aggiunte

  • Correggi la logica del livello di errore
  • Implementa un loop / sub DoWork che scorre attraverso il numero e esegue alcune operazioni aritmetiche

:::::::::::::::
::CountTo.bat
:::::::::::::::
@echo off

::This is the number to test
if "%1"=="" goto :Usage

set param=%1
set matchPattern="^[1-9][0-9]*$"

::test if param matches matchPattern, quietly
:: (redirect stdout to nul, and stderr to stdout)

echo %param%|findstr /r %matchPattern%>nul 2>&1

:: check for errorlevel 1 or higher.  errorlevel 0 is handled as
:: an unchecked fall-through
if errorlevel 1 goto :MyHandleErrorCode

::Success (errorlevel ! >= 1) so proceed.
echo %param% is a valid number
echo  (matches findstr /r %param% %matchPattern%)
echo  findstr returned errorlevel 0

::any other code that the batch file needs to do goes here
echo.
echo Iterating from 1 to %param%
echo.
for /l %%i in (1,1,%param%) do call :DoWork %%i

::anything else,
:: .
:: .

::cleanup
:: .
:: .

::exit the batch file here, skipping embedded subroutines
goto :eof

:::::::::::::::::::::::::
:: Main work subroutine
:::::::::::::::::::::::::
:DoWork
set /a offset = %1 - 1
set /a square = %1 * %1
echo item %1
echo   offset: %offset%
echo   square: %square%
echo.
goto :eof

:::::::::::::::::::::::
:: Error handler code
:::::::::::::::::::::::
:MyHandleErrorCode
echo.
echo CountTo %param%
echo   %param% is not a valid number
echo   (does not match findstr /r %param% %matchPattern%)
echo   findstr returned errorlevel ^>= 1
:: error code doesn't have a goto :eof, we want to drop through to :Usage

::::::::
:Usage
::::::::
echo.
echo Usage:
echo.   CountTo ^<someNumber^>

Il problema con quanto segue è che restituisce sempre "Numero valido" perché "se il livello di errore 0" è sempre vero a causa del fatto che è un confronto "> = 0", non un confronto "== 0".

@echo off

set param=%1

echo %param%| findstr /r "^[1-9][0-9]*$">nul

if errorlevel 0 (
    echo Valid number
)

i miei $ 0,02


Whoops ... risolto il livello di errore anche sul mio. Confronto numerico diretto piuttosto che fall-through automatico.
Bob,

2

Puoi convalidare qualsiasi variabile se il suo numero:

SET "var="&for /f "delims=0123456789" %i in ("%a") do set var=%i
if defined var (echo."NIC">nul) else (echo."number")

0
set xx=33
echo %xx%
SET /a %xx%+0 2>nul >nul && echo all Digits


set xx=3x3
echo %xx%
SET /a %xx%+0 2>nul >nul || echo No Digits

2
Puoi aggiungere anche qualche spiegazione, per favore?
Slhck,

0

Non so perché ma sul mio sistema il findstrcomando non ha funzionato. Il livello di errore non veniva modificato in corrispondenza o nessuna corrispondenza.

Ho escogitato un altro metodo però

:: Look for all digits. Parse the string and use all the digits as
:: delimiters. If the entire string is a digit then we will get an empty
:: parse value.
SET ALL_DIGITS=0
FOR /F "tokens=* delims=0123456789" %%a IN ("%VALUE%") DO (
    IF "[%%a]" EQU "[]" SET ALL_DIGITS=1
)

IF %ALL_DIGITS% EQU 0 (
    ECHO ERROR: %VALUE% is not all numbers
)

-1
:main 
set /p input=text
if %input% equ 0 goto valid
set /a inputval="%input%"*1
if %inputval% equ 0 goto invalid
goto valid

:invalid
echo Input is not an integer.

:valid
echo Input is an integer.

Ecco un gioco che utilizza questa funzione.

@echo off
:main
set /a guessmin=1
set /a guessmax=100
set /a guessrand=%random% %%100 +1
echo.
:check
if %guessmin% equ %guessmax% goto fail
set /p input=- Pick a number %guessmin% - %guessmax%: 
set /a inputval="%input%"*1
if %inputval% equ 0 goto invalid
if %inputval% gtr %guessmax% goto invalid
if %inputval% lss %guessmin% goto invalid
if %inputval% gtr %guessrand% goto high
if %inputval% lss %guessrand% goto low
if %inputval% equ %guessrand% goto mid
:invalid
echo   Please enter a valid number.
echo.
goto check
:high
echo   Your guess was too high.
echo.
set /a guessmax=%inputval%-1
goto check
:low
echo   Your guess was too low.
echo.
set /a guessmin=%inputval%+1
goto check
:mid
echo   Your guess was correct. The game will now reset.
set /p input=- Press enter to play again.
cls
goto main
:fail
echo   You actually managed to lose because there is only
echo   one number remaining. That number is %guessrand%.
set /p input=- Press enter to lose again.
cls
goto main
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.