1

我需要写一个脚本,in.bat,在哪里

  • 用户输入一个 3 位数字(作为字符串) i。
  • 该脚本有 4 组预定义的数字,数字从 1 到 4
  • 该脚本测试组中 i 的成员资格,并返回包含 i 的组的索引。

我不熟悉为批处理文件声明和初始化任何类型的数据结构(例如列表、数组等),所以有人可以帮助我吗?

伪代码:

::Returns 1,2,3,4,5 Depending on testNum passed
group1= <822-824,829,845,851,859,864,867>
group2= <826-828,830-839,843-844,847-850,852-854,860-862,883>
group3= <855-858,861,863,865>
group4= <877-882,884>
if %1 is member of group1 
return 1
if %1 is member of group2
return 2
if %1 is member of group3
return 3
if %1 is member of group4
return 4

谢谢!

4

4 回答 4

1

这将设置GROUP为在其中找到代码的任何组

set test=822,823,824,829,845,851,859,864,867
echo %test% | findstr %1>nul&&set group=1
set test=826,827,828,830,831,832,833,834,835,836,837,838,839,843,844,847,848,849,850,852,853,854,860,861,862,883
echo %test% | findstr %1>nul&&set group=2
set test=855,856,857,858,861,863,865
echo %test% | findstr %1>nul&&set group=3
set test=877,878,879,880,881,882,884
echo %test% | findstr %1>nul&&set group=4

如果要用于测试ERRORLEVEL返回值,则将SET GROUP=EXIT /B

于 2012-07-02T21:47:36.223 回答
1

绝不是完美的,而是一个工作的起点。将以下脚本另存为group.bat并调用它group 878以找出 878 属于哪个组。

@echo off

SET group1=822-824,829,845,851,859,864,867
SET group2=826-828,830-839,843-844,847-850,852-854,860-862,883
SET group3=855-858,861,863,865
SET group4=877-882,884

CALL :IsInGroup %1 "%group1%"
IF Errorlevel 1 echo Group 1 & GOTO :EOF

CALL :IsInGroup %1 "%group2%"
IF Errorlevel 1 echo Group 2 & GOTO :EOF

CALL :IsInGroup %1 "%group3%"
IF Errorlevel 1 echo Group 3 & GOTO :EOF

CALL :IsInGroup %1 "%group4%"
IF Errorlevel 1 echo Group 4 & GOTO :EOF

echo Group not found
GOTO :EOF

:IsInGroup
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%i IN (%~2) DO (
    SET h=%%i
    SET g=!h:~3,1!
    SET /a lo=!h:~0,3!

    IF !g!. == -. (
        SET /a hi=!h:~4,3!
        IF %1 GEQ !lo! (
            IF %1 LEQ !hi! exit /B 1
        )
    ) ELSE (
        IF %1 EQU !lo! exit /B 1
    )
)
ENDLOCAL
EXIT /B 0

该函数:IsInGroup检查第一个参数是否包含在作为第二个参数传递的列表中。

于 2012-07-02T21:59:17.320 回答
1

Batch 没有任何正式的复杂数据结构,如数组、列表或对象。但是你可以模仿他们。这是一个有效的解决方案,它定义了与您的问题中的格式几乎相同的组。

@echo off
setlocal enableDelayedExpansion

::Here is a small loop to test the routine
for %%N in (822,823,883,835,856,863,880,884) do (
  call :assignGroup %%N
  echo %%N is in group !group!
)
exit /b

:assignGroup  CaseNumber
:: The returning value is contained in variable GROUP
set group=0
for %%A in (
  "822-824,829,845,851,859,864,867"
  "826-828,830-839,843-844,847-850,852-854,860-862,883"
  "855-858,861,863,865"
  "877-882,884"
) do (
  set /a group+=1
  for %%B in (%%~A) do (
    for /f "tokens=1,2 delims=-" %%C in ("%%B") do (
      if "%%C"=="%~1" exit /b
      if "%~1" gtr "%%C" if "%~1" leq "%%D" exit /b
    )
  )
)
::no group found so undefine the var
set "group="
exit /b

上述解决方案适用于偶尔调用。但是,如果您要调用该例程数千次,那么最好用分配的组号初始化一个有效值数组。然后每个测试都直接读取值,而不必调用例程。但是,有可能滥用这种技术。分配足够的值,每个变量分配变得越来越慢。您可能还会花费更多时间来设置数组而不是实际测试值。

[].请注意,变量名称中的字符没有意义。它们可以从变量名中去掉,代码的功能也相同。它们只是为了帮助理解变量的意图。

@echo off
setlocal enableDelayedExpansion

::initialize a sparse "array" that assigns a group to each valid case #
set group=0
for %%A in (
  "822-824,829,845,851,859,864,867"
  "826-828,830-839,843-844,847-850,852-854,860-862,883"
  "855-858,861,863,865"
  "877-882,884"
) do (
  set /a group+=1
  for %%B in (%%~A) do (
    for /f "tokens=1,2 delims=-" %%C in ("%%B") do (
      if "%%D"=="" (
        set case[%%C].group=!group!
      ) else for /l %%N in (%%C 1 %%D) do (
        set case[%%N].group=!group!
      )
    )
  )
)

::Now test some values
for %%N in (822,823,883,835,856,863,880,884,900) do (
  if defined case[%%N].group (
    echo %%N is in !case[%%N].group!
  ) else (
    echo %%N is not in a group
  )
)
exit /b
于 2012-07-02T23:18:51.263 回答
1

如果每组中要检查的值的数量很少,则 dbenhams 第二种方法(直接读取每个数组值)是最快的。在 FOR 循环中处理每个组的值以进行单独或范围比较的任何其他方法都比较慢。但是,随着单个元素数量的增加(计算范围内包含的每个元素),数组值方法会变慢,如 dbenhams 所示。

还有另一种使用算术表达式来解决此问题的方法。例如,您可以使用以下命令检查变量是 829 还是 845:

set /A result=(829-variable)*(845-variable)

如果变量具有这两个值中的任何一个,则结果为零。要检查变量是否在范围内,表达式如下:

set /A aux=(lowerLimit-variable)*(variable-upperLimit), result=(aux-1)/aux

前面的表达式需要一个小的规定,以防变量是任何限制(管理除以零)。下面的程序为每个组组装适当的算术表达式;之后,通过最多 4 个 SET /A 命令(每组一个)来检查每个值。这种方法比在 FOR 循环中单独测试每个值更快,并且每组只使用一个变量,而不是每个单独的元素。

@echo off
setlocal EnableDelayedExpansion

rem Assemble testing expression for each group
set numGroup=0
for %%a in (
   "822-824,829,845,851,859,864,867"
   "826-828,830-839,843-844,847-850,852-854,860-862,883"
   "855-858,861,863,865"
   "877-882,884"
   ) do (
   set expr=1
   for %%b in (%%~a) do (
      for /F "tokens=1,2 delims=-" %%c in ("%%b") do (
         if "%%d" equ "" (
            rem Individual value: multiply previous expr by direct subtract
            set "expr=!expr!*(%%c-n^)"
         ) else (
            rem Range value pair: use range expression at this point, then continue
            set "expr=!expr!,a=r,r=0,b=(%%c-n^)*(n-%%d),r=(b-1)/b*a"
         )
      )
   )
   set /A numGroup+=1
   set expr[!numGroup!]=!expr!
)

rem Now test some values
for %%n in (822,823,883,835,855,856,858,863,880,884,900) do (
   call :assignGroup %%n
   echo %%n is in group !group!
)
goto :EOF

:assignGroup number
set /A n=%1, group=0
for /L %%i in (1,1,%numGroup%) do (
   set /A r=!expr[%%i]! 2> NUL
   if !r! equ 0 set group=%%i & exit /B 0
)
exit /B 1
于 2012-07-03T11:58:27.187 回答