Verifique solo la entrada numérica en el archivo por lotes

10

En la línea de comandos basada en Windows NT (principalmente para XP o superior), ¿hay alguna forma de verificar si un interruptor proporcionado es solo un número? Dependiendo del número, quiero que recorra el código x número de veces

Lucas canadiense
fuente
1
Personalmente, prefiero el método en esta respuesta para: Asegúrese de que el usuario haya ingresado un número entero . Use el procesador de comandos para hacer todo ese trabajo. Puede simplificarlo a 2 x líneas como una solución mínima: 1 set /a NO_LINES=%~1.; 2 if %NO_LINES% NEQ %~1 goto ABORT.. Cuando los dos son iguales: la variable o parámetro es numérico .
será el

Respuestas:

18

Editado para arreglar la expresión regular según el comentario de debham . Resulta que agregar un espacio antes de la tubería después del eco agrega un espacio a la cadena canalizada, que fue lo que rompió la coincidencia de inicio / final de línea anteriormente. La expresión regular podría mejorarse aún más descartando espacios en blanco al principio y al final.


Ahí está el findstrcomando. Puede buscar archivos con expresiones regulares, al igual que grepen Linux. También puede buscar entradas canalizadas.

@echo off

set param=%1

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

if %errorlevel% equ 0 (
    echo Valid number
)

Explicación

El parámetro utilizado se establece en la paramvariable. Sin embargo, no hay nada que lo detenga utilizando el parámetro directamente ( %1para el primer parámetro ).

findstrse usa para buscar la entrada canalizada con la /rbandera para expresiones regulares.

El patrón:

  • ^ significa comienzo de línea.

  • [0-9]significa un dígito. El *significa el anterior repetido cero o más veces. Entonces [0-9][0-9]*significa un dígito, más cero o más dígitos. En otras palabras, al menos un dígito. Los +no parece ser apoyado por una o más veces findstr. Tenga en cuenta que [1-9]se usa para el primer dígito para no permitir los ceros a la izquierda; vea los comentarios.

  • $ significa fin de línea.


Ahora, un bucle for en lote por x número de veces ... si x no es un número válido, el bucle en realidad no se ejecuta en absoluto, simplemente se omite para la siguiente línea. ¡Entonces no hay necesidad de verificar si la entrada es un número válido!

@echo off

set param=%1

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

El ciclo se realiza utilizando for /l, donde los (x,y,z)medios comienzan en x, incrementan yhasta que zse alcanza. Y se establece %%aen el número / iteración actual.

Nota: esto realmente falla si hay un cero inicial, lo que hace que el procesador de comandos lo trate como un número octal. Vea la respuesta de dbenham para una mejor solución.

Beto
fuente
Excelente explicación! Y fácil de usar
canadiense Luke
1
Tal como está escrito, esta solución fallará con un parámetro como "this 1 fails"The FINDSTR debe hacer una coincidencia exacta. No debería hacer una coincidencia de palabras.
dbenham
@dbenham Gracias. Intenté la coincidencia de inicio / final de línea antes, pero eso falló debido a que el eco pasaba un espacio adicional. Corregido ahora.
Bob
@CanadianLuke Es posible que desee echar un vistazo a la edición.
Bob
Un valor de 09o 010podría causar problemas debido a la notación octal. Vea mi respuesta para expresiones regulares que no permite la notación octal.
dbenham
8

Lo siguiente funciona muy bien para mí. SET /a param=%1+0siempre devuelve 0si %1está vacío o no es numérico. De lo contrario, proporciona el número dado.

SET /a param=%1+0
IF NOT %param%==0 ECHO Valid number
Andreas
fuente
44
Esto fallará si el parámetro = 0. También tratará un parámetro como "1 + 1" como un número, lo que puede causar problemas, según los requisitos.
dbenham
7

Esto detectará si el primer parámetro es un número natural válido (entero no 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
)

Si desea permitir cotizaciones alrededor del número, entonces

@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: los ceros iniciales no se permiten porque el lote los trata como octales, por lo que un valor como 09no es válido y 010tiene un valor de 8.

dbenham
fuente
3

Inspirado por la excelente respuesta de Bob con las siguientes adiciones

  • Repara la lógica de nivel de error
  • Implemente un bucle / sub DoWork que recorra el número y realice algunos cálculos aritméticos.

:::::::::::::::
::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^>

El problema con lo siguiente es que siempre devuelve 'Número válido' porque 'si errorlevel 0' siempre es verdadero debido al hecho de que es una comparación '> = 0', no una comparación '== 0'.

@echo off

set param=%1

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

if errorlevel 0 (
    echo Valid number
)

mis $ .02

TecladoJockey
fuente
Whoops ... también arregló el errorlevel en el mío. Comparación numérica directa en lugar de la caída automática.
Bob
2

Puede validar cualquier variable si su número:

SET "var="&for /f "delims=0123456789" %i in ("%a") do set var=%i
if defined var (echo."NIC">nul) else (echo."number")
Krzysztof Gapski
fuente
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
Gregor Weertman
fuente
2
¿Puedes agregar alguna explicación también, por favor?
slhck
0

No sé por qué, pero en mi sistema el findstrcomando no funcionó. El nivel de error no se modificaba en la coincidencia o no coincidencia.

Sin embargo, se me ocurrió otro método

:: 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
)
John Rocha
fuente
-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.

Aquí hay un juego que usa esta función.

@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
AlzaLuna
fuente