我正在使用启用二进制操作的cmd上编写计算器。我需要验证输入数据(删除字母和算术运算不需要的其他符号)
@echo off
set data=
echo %* | findstr /R "\/\? ECHO" > nul
IF "%ERRORLEVEL%" EQU "0" goto printHelp
:main
set data= %data%%1
shift
if "%1" == "" (
echo %data% | findstr /R "^[0123456789*-+()/%!^_&|]*$" >nul 2>&1
if "%ERRORLEVEL%" EQU 0 (
echo Incorrect input data
exit /B
)
goto :result
) else (
goto :main
)
:result
set /a data="%data%"
echo %data%
exit /B
:printHelp
echo.
echo --------------------------------------------------
echo Using: calculator.bat [/?] [EXPRESSION]
echo helps you to consider arithmetic in Command Line
echo --------------------------------------------------
exit /B
我的正则表达式无效。也不认为是二进制操作。可能是什么问题?
答案 0 :(得分:2)
第1部分 - 为什么“正则表达式无效”
你的逻辑错了。如果匹配,FINDSTR将ERRORLEVEL设置为0,如果不匹配则设置为1。您的正则表达式验证所有字符都是“有效”,但您的条件是将匹配视为不正确的输入。
您的IF语句在一方使用引号,但在另一方使用。您必须保持一致,否则永远无法评估为真。
百分比文字必须在批处理脚本中加倍。您的正则表达式具有应写为%%
的文字百分比。
在设置值的同一代码块中使用%ERRORLEVEL%。这不起作用,因为在解析代码块时会扩展该值 - 在设置值之前。
最简单的替代方法是使用if errorlevel 1
,如果ERRORLEVEL为> = 1则返回true。
另一种选择是在顶部使用SETLOCAL ENABLEDELAYEDEXPANSION启用延迟扩展,然后使用if !errorlevel! neq 0
。但这需要将正则表达式中引用的!
字面值转义为^!
,并将^
字面值转义为^^
。
我最喜欢的选项是使用&&
和||
条件运算符而不是IF。
findstr ... >nul && (match found statements) || (no match statements)
在您的情况下,如果没有匹配项,您希望采取措施,因此您只需要||
运算符。
第2部分 - 为什么你的整个概念不是一个好主意
您的验证过于简单化。简单地筛选出无效字符并不能防止错误。例如,即使所有字符都“有效”,1**2
也会导致错误。还有许多其他带有“有效”字符的输入会导致错误。
SET / A可以直接使用环境变量。它知道如何在不扩展代码中的值的情况下访问该值。这可以是一个强大的工具。计算中使用的变量名称可以包括不是运算符的任何字符。因此可以说,SET / A计算没有无效字符。排除“无效”字符会阻止在计算中使用变量。
下面是我前段时间写的一个简单的批处理计算器程序。它在无限循环中请求输入并显示结果,直到您输入退出命令。它支持SET / A支持的所有运算符。
它允许您在表达式中定义和使用变量。最近计算的结果始终存储在名为#
的变量中。
计算器可以将结果显示为十进制,十六进制或二进制。
默认情况下,它仅显示上次计算的结果。可以指示在每次计算后也显示所有变量的值。
您可以输入命令而不是数学计算。所有命令均以\
\
退出
\V
切换变量列表ON或OFF
\D
十进制模式 - 结果显示为十进制
\H
十六进制模式 - 结果显示为十六进制
\B
二进制模式 - 结果显示为二进制
\C X
清除变量X
\C *
清除所有变量
\C X*
清除所有以X开头的变量
不输入任何内容将列出所有当前定义的变量。
清除变量未定义。请注意,未定义的变量的隐含值为0.
以下是代码:
@echo off
setlocal enableDelayedExpansion
for /f "delims==" %%v in ('set') do set %%v=
set __skip=#COMSPEC#PATHEXT#PROMPT#__mode#__str#__skip#__clr###__dispVars#
set __mode=Dec
set __dispVars=0
:top
echo:
set __str=
set /p "__str=%__mode%> "
if "!__str!"=="\" exit /b
if "!__str!"=="" call :dispVar # & call :dispVars & goto :top
if /i "!__str:~0,2!"=="\C" call :clearVars &goto :top
if /i "!__str!"=="\H" (set __mode=Hex) ^
else if /i "!__str!"=="\D" (set __mode=Dec) ^
else if /i "!__str!"=="\B" (set __mode=Bin) ^
else if /i "!__str!"=="\V" (set /a "__dispVars=^!__dispVars") ^
else set /a #=(!__str!)
call :dispVar #
if !__dispVars! gtr 0 call :dispVars
goto :top
:clearVars
for /f "delims=,; " %%v in ("!__str:~2!") do (
set __clr=%%v
if "!__clr:~-1!"=="*" (
set __clr=!__clr:~0,-1!
for /f "delims==" %%x in ('set !__clr!') do (
if "!__skip:#%%x#=!"=="!__skip!" set "%%x="
)
) else set "%%v="
)
call :dispVar #
call :dispVars
exit /b
:dispVars
setlocal
for /f "tokens=1,2 delims==" %%v in ('set') do if "!__skip:#%%v#=!"=="!__skip!" call :dispVar %%v
exit /b
:dispVar Var
setlocal
if !__mode!==Hex call :num2hex %1 disp
if !__mode!==Bin call :num2bin %1 disp
if !__mode!==Dec set /a disp=!%~1!
set var=%~1
if "!var:~0,6!"=="!var!" (
set "var=!var! ----------"
set "var=!var:~0,6!"
)
echo %var% = !disp!
exit /b
:num2hex NumVal RtnVar
setlocal enabledelayedexpansion
set hex=
set /a "dec=%~1"
set "map=0123456789ABCDEF"
for /l %%n in (1,1,8) do (
set /a "d=dec&15,dec>>=4"
for %%d in (!d!) do set "hex=!map:~%%d,1!!hex!"
)
(endlocal & rem return values
set %~2=%hex%
exit /b
)
exit /b
:num2bin NumVal RtnVar
setlocal enabledelayedexpansion
set bin=
set /a "dec=%~1"
for /l %%n in (1,1,32) do (
set /a "d=dec&1,dec>>=1"
set "bin=!d!!bin!"
)
(endlocal & rem return values
set %~2=%bin%
exit /b
)
exit /b
以下是短期会议的结果:
D:\test>calculate.bat
Dec> 2*3
# ---- = 6
Dec> a=#+1
# ---- = 7
Dec>
# ---- = 7
a ---- = 7
Dec> b=(a+=5)*2
# ---- = 24
Dec> \v
# ---- = 24
a ---- = 12
b ---- = 24
Dec> c=b/3
# ---- = 8
a ---- = 12
b ---- = 24
c ---- = 8
Dec> \h
# ---- = 00000008
a ---- = 0000000C
b ---- = 00000018
c ---- = 00000008
Hex> \b
# ---- = 00000000000000000000000000001000
a ---- = 00000000000000000000000000001100
b ---- = 00000000000000000000000000011000
c ---- = 00000000000000000000000000001000
Bin> \
D:\test>