regex - 正则表达式批处理

标签 regex batch-file cmd

我正在使用启用了二进制运算的 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

我的正则表达式不起作用。也不认为是二元运算。可能是什么问题?

最佳答案

第 1 部分 - 为什么您的“正则表达式不起作用”

  • 你的逻辑是错误的。如果有匹配项,FINDSTR 将 ERRORLEVEL 设置为 0,如果没有匹配项,则设置为 1。您的正则表达式正在验证所有字符是否“有效”,但您的条件将匹配项视为错误输入。

  • 您的 IF 语句在一侧使用引号,但在另一侧不使用。您必须保持一致,否则它永远无法评估为 TRUE。

  • 百分比文字必须在批处理脚本中加倍。您的正则表达式有一个百分比文字,应该写成 %%

  • 您在设置值的同一代码块中使用 %ERRORLEVEL%。这是行不通的,因为在解析代码块时会扩展值 - 在设置值之前。

    最简单的替代方法是使用 if errorlevel 1,如果 ERRORLEVEL >= 1,则返回 true。

    另一种选择是在顶部使用 SETLOCAL ENABLEDELAYEDEXPANSION 启用延迟扩展,然后使用 if !errorlevel! neq 0。但这需要将正则表达式中引用的 ! 文字转义为 ^!,并将 ^ 文字转义为 ^^.

    我最喜欢的选择是使用 &&|| 条件运算符而不是 IF。

    findstr ... >nul && (匹配找到的语句) || (没有匹配语句)

    在您的情况下,您希望在没有匹配项时采取行动,因此您只需要 || 运算符。

第 2 部分 - 为什么您的整个概念不是一个好主意

  • 您的验证过于简单。简单地筛选出无效字符并不能防止错误。例如,1**2 将导致错误,即使所有字符都是“有效的”。还有许多其他带有“有效”字符的输入会导致错误。

  • SET/A 可以直接使用环境变量。它知道如何在不扩展代码中的值的情况下访问该值。这可能是一个强大的工具。计算中使用的变量名称可以包含任何不是运算符的字符。因此可以争辩说 SET/A 计算没有无效字符。排除“无效”字符会阻止在计算中使用变量。


下面是我前段时间写的一个简单的批量计算器程序。它处于请求输入和显示结果的无限循环中,直到您输入退出命令。它支持 SET/A 支持的所有运算符。

它允许您在表达式中定义和使用变量。最近计算的结果始终存储在名为 # 的变量中。

计算器可以将结果显示为十进制、十六进制或二进制。

默认情况下,它只显示最后一次计算的结果。可以指示它在每次计算后也显示所有变量的值。

您可以输入命令而不是数学计算。所有命令都以 \

开头

\ 退出
\V 打开或关闭变量列表
\D 十进制模式 - 结果显示为十进制
\H 十六进制模式 - 结果显示为十六进制
\B 二进制模式 - 结果显示为二进制
\C X 清除变量 X
\C * 清除所有变量
\C X*清除所有以X开头的变量

不输入任何内容将列出所有当前定义的变量。

清除的变量是未定义的。请注意, undefined variable 的隐式值为 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

这是一个简短 session 的结果:

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>

关于regex - 正则表达式批处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26408773/

相关文章:

java - 使用同一组捕获 <thisPartOnly> 和 (thisPartOnly)

javascript - 如何按正则表达式模式拆分并将分隔符保留在长字符串上?

regex - 为什么使用 NFA 而不是 DFA

PHP: shell_exec();与 cmd 工作不一样? [WIN10命令行]

batch-file - 仅在周一和周四运行 CMD 批处理文件

java - 如何在 Android Java 中合并正则表达式中的两个或多个条件?

Powershell Putty 连接和自动化任务

windows - 从 Windows 批处理变量中获取子字符串

batch-file - 批量设置置顶标题

windows - DOS/Windows 批处理文件 (.BAT) 中 SET 后的 REG 命令为 "unknown"