Проверка только числового ввода в пакетном файле

Вопрос или проблема

В командной строке, основанной на Windows NT (в основном для XP или выше), есть ли способ проверить, является ли переданный параметр только числом? В зависимости от числа, я хочу, чтобы он выполнял код x раз.

Отредактировано, чтобы исправить регулярное выражение согласно комментарию debham. Оказалось, что добавление пробела перед символом трубы после echo добавляет пробел к строке, что нарушало сопоставление начала и конца строки. Регулярное выражение можно улучшить, исключив пробелы в начале и в конце.


Есть команда findstr. Она может искать файлы с помощью регулярных выражений, подобно grep в Linux. Она также может искать переданные на вход данные.

@echo off

set param=%1

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

if %errorlevel% equ 0 (
    echo Valid number
)

Объяснение

Параметр устанавливается в переменную param. Однако ничто не мешает вам использовать параметр напрямую (%1 для первого параметра).

findstr используется для поиска в переданном на вход потоке с флагом /r для регулярного выражения.

Шаблон:

  • ^ означает начало строки.

  • [0-9] означает цифру. * означает предыдущее повторенное ноль или более раз. Таким образом, [0-9][0-9]* означает одну цифру плюс ноль или более цифр. Другими словами, по крайней мере, одну цифру. + одно или более раз, кажется, не поддерживается findstr. Учтите, что [1-9] используется для первой цифры, чтобы исключить нули в начале – см. комментарии.

  • $ означает конец строки.


Теперь, цикл в батч-файле, выполняющий x раз… если x не является допустимым числом, цикл вообще не выполняется — он просто пропускается для следующей строки. Поэтому нет необходимости проверять, является ли вводимое значение допустимым числом!

@echo off

set param=%1

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

Цикл выполняется с использованием for /l, где (x,y,z) означает начать с x, увеличивать на y, пока z не будет достигнуто. И он устанавливает %%a в текущее число/итерацию.

Примечание: это фактически не работает, если есть начальний ноль, приводя командный процессор к интерпретации его как восьмеричного числа. См. ответ dbenham для более лучшего решения.

Следующее работает очень хорошо для меня. SET /a param=%1+0 всегда возвращает 0, если %1 пусто или не является числом. В противном случае он возвращает переданное число.

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

Это определит, является ли первый параметр допустимым натуральным числом (неотрицательным целым числом).

@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
)

Если вы хотите разрешить кавычки вокруг числа, то

@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
)

Примечание — начальные нули запрещены, потому что батч обрабатывает их как восьмеричные, так что значение вроде 09 недопустимо, а 010 имеет значение 8.

Вдохновлено превосходным ответом Боба с добавлением следующих улучшений

  • Исправление логики errorlevel
  • Реализация цикла DoWork, который проходит по числу и выполняет некоторую арифметику

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

::Это число для проверки
if "%1"=="" goto :Usage

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

::проверка, соответствует ли param шаблону matchPattern, без вывода
:: (перенаправление stdout в nul, и stderr в stdout)

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

:: проверка code errorlevel 1 или выше. errorlevel 0 обрабатывается как
:: падение без проверки
if errorlevel 1 goto :MyHandleErrorCode

::Успех (errorlevel ! >= 1) так что продолжаем.
echo %param% is a valid number
echo  (совпадает с findstr /r %param% %matchPattern%)
echo  findstr вернул errorlevel 0

::любой другой код, который должен выполняться в батч-файле, располагается  
echo.
echo Итерация с 1 до %param%
echo.
for /l %%i in (1,1,%param%) do call :DoWork %%i

::что-то еще,
:: .
:: .

::очистка
:: .
:: .

::выход из батч-файла здесь, пропуская встраиваемые подпрограммы
goto :eof

:::::::::::::::::::::::::
:: Основная рабочая подпрограмма
:::::::::::::::::::::::::
:DoWork
set /a offset = %1 - 1
set /a square = %1 * %1
echo элемент %1
echo   смещение: %offset%
echo   квадрат: %square%
echo.
goto :eof

:::::::::::::::::::::::
:: Код обработки ошибок
:::::::::::::::::::::::
:MyHandleErrorCode
echo.
echo CountTo %param%
echo   %param% не является допустимым числом
echo   (не совпадает с findstr /r %param% %matchPattern%)
echo   findstr вернул errorlevel ^>= 1
:: код ошибки не имеет goto :eof, мы хотим упасть в :Usage

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

Проблема с следующим в том, что он всегда возвращает ‘Valid number’, потому что ‘if errorlevel 0’ всегда истинно, так как это сравнение ‘>= 0’, а не ‘== 0’.

@echo off

set param=%1

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

if errorlevel 0 (
    echo Valid number
)

мои 2 копейки

Вы можете проверить любую переменную, является ли она числом:

SET "var="&for /f "delims=0123456789" %i in ("%a") do set var=%i
if defined var (echo."NIC">nul) else (echo."number")
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

Я не знаю, почему, но в моей системе команда findstr не работала. Уровень ошибок не изменялся на совпадении или несопадении.

Я придумал другой метод

:: Найти все цифры. Проанализировать строку и использовать все цифры в качестве
:: разделителей. Если вся строка — цифра, то мы получим пустое
:: значение.
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
)

Один подход:

set test_var=001
( 
  (if errorlevel %test_var% break ) 2>nul
)&&(
  echo %test_var% is numeric
)||(
  echo %test_var% is NOT numeric
)

set test_var=001X
( 
  (if errorlevel %test_var% break ) 2>nul
)&&(
  echo %test_var% is numeric
)||(
  echo %test_var% is NOT numeric
)

Другой:

@echo off 

:isInterer  input [returnVar] 
setlocal enableDelayedexpansion 
set "input=%~1" 

if "!input:~0,1!" equ "-" (
    set "input=!input:~1!"
) else (
    if "!input:~0,1!" equ "+" set "input=!input:~1!"
)

for %%# in (1 2 3 4 5 6 7 8 9 0) do ( 
        if not "!input!" == "" ( 
                set "input=!input:%%#=!" 
    )         
) 

if "!input!" equ "" ( 
        set result=true 
) else ( 
        set result=false 
) 

endlocal & if "%~2" neq "" (set %~2=%result%) else echo %result% 

Однострочная подпрограмма для получения допустимого числа из любого ввода, возвращаемое число на errorlevel, гораздо быстрее, чем вызов findStr, возвращает 0, если не действителен (не всегда 0, нужно проверять подробнее), выведет “случайное” при выходе за пределы диапазона longInt:

@echo off
set x=*non987digits987start987returns0*
call :GetNum %x%
echo %errorlevel%

set x=123first987digits987returned
call :GetNum %x%
echo %errorlevel%
pause
goto :eof

:GetNum
exit /b %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.

Вот игра, использующая эту функцию.

@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   Пожалуйста, введите действительное значение.
echo.
goto check
:high
echo   Ваше предположение было слишком высоким.
echo.
set /a guessmax=%inputval%-1
goto check
:low
echo   Ваше предположение было слишком низким.
echo.
set /a guessmin=%inputval%+1
goto check
:mid
echo   Ваше предположение было верным. Игра сейчас перезагрузится.
set /p input=- Нажмите Enter, чтобы сыграть снова.
cls
goto main
:fail
echo   Вы действительно умудрились проиграть, потому что осталось только
echo   одно число. Это число %guessrand%.
set /p input=- Нажмите Enter, чтобы снова проиграть.
cls
goto main

.

Ответ или решение

Для проверки того, является ли предоставленный переключатель в пакетном файле числом, в Windows NT-подобных системах, существует несколько подходов. Разберем основные методы, которые помогут вам в данной задаче.

Теория

В сценариях пакетных файлов для операционных систем на базе Windows часто требуется проверить, является ли данная входная величина числом, чтобы избежать ошибок при выполнении циклов или подборок параметров. Одним из наиболее удобных инструментов для анализа в пакетных файлах является команда findstr, которая позволяет работать с регулярными выражениями схожим образом с grep в Linux. Этот инструмент может использоваться для поиска в строках, передаваемых через конвейер.

Пример

Проверка с использованием findstr

Пример кода ниже демонстрирует применение команды findstr для проверки, является ли входное значение натуральным числом (положительным целым числом без ведущих нулей):

@echo off
set param=%1
echo %param% | findstr /r "^[1-9][0-9]*$" >nul
if %errorlevel% equ 0 (
    echo Valid number
)

Объяснение:

  1. Регулярное выражение ^[1-9][0-9]*$ обозначает строку, которая начинается с цифры от 1 до 9, за которой может следовать любое количество цифр от 0 до 9. Этот шаблон предотвращает наличие ведущих нулей.
  2. findstr с ключом /r указывает, что для поиска используются регулярные выражения.
  3. Проверка errorlevel: команда if %errorlevel% equ 0 используется для проверки успешности поиска. Если регулярное выражение найдет совпадение, переменная %errorlevel% будет равна 0.

Применение

Помимо проверки, действительно ли значение является числом, в случае положительного подтверждения вы можете выполнить цикл столько раз, сколько указано в параметре. Например:

@echo off
set param=%1
for /l %%a in (1,1,%param%) do (
    echo %%a
)

Описание цикла:

  • for /l используется для создания циклов в пакетных файлах. Синтаксис (start,step,end) означает, что цикл начнется с start, будет увеличиваться на step и завершится на end. В нашей задаче, если param – валидное число, цикл выполнится именно столько раз.

Замечание: При использовании чисел с ведущими нулями, такие как 09 или 010, пакетный процессор может неправильно обрабатывать их как восьмеричные числа.

Альтернативные методы

Если команда findstr по какой-либо причине не работает, можно использовать арифметические операции. Например:

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

Здесь SET /a выполняет арифметическое выражение, что в случае нечислового значения даст результат 0, что можно использовать для последующей логики проверки.

Примеры сложного использования

Если вам требуется расширенная логика с обработкой ошибок или выполнением различных операций по найденному числу, можно реализовать это, добавив обработку ошибок и подпрограммы:

@echo off
:: Проверка на корректность числа
if "%1"=="" goto :Usage

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

:: Проверка соответствия шаблону
echo %param%|findstr /r %matchPattern%>nul 2>&1
if errorlevel 1 goto :MyHandleErrorCode

:: Выполнение основного кода, если число корректно
echo %param% is a valid number
echo.
for /l %%i in (1,1,%param%) do call :DoWork %%i

goto :eof

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

:MyHandleErrorCode
echo.
echo %param% is not a valid number
goto :Usage

:Usage
echo.
echo Usage:
echo.   script.bat <number>

Этот скрипт не только проверяет числа, но и выполняет операции с каждым значением в цикле, используя подпрограмму :DoWork для вычислений. Подобный уровень детализации и гибкости делает этот метод полезным в сложных сценариях.

Понимание работы с числовыми параметрами в пакетных файлах важно для создания надежных и эффективных скриптов. Использование команд findstr, for /l, и арифметических методов позволяет достигнуть высокой степени точности и функциональности вашей программы.

Оцените материал
Добавить комментарий

Капча загружается...