1

スクリプト in.bat を作成する必要があります。

  • ユーザーは 3 桁の数字を (文字列として) 入力します i.
  • スクリプトには、1 から 4 までの数字の 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

各グループでチェックする値の数が少ない場合は、dbenhamsの2番目の方法(各配列値の直接読み取り)が最速です。FORループ内の各グループの値を処理して、個別の比較または範囲の比較を行う他の方法は低速です。ただし、個々の要素の数が増えると(範囲内に含まれる各要素を数える)、dbenhamsが示しているように、配列値の方法は遅くなります。

aritmethic式を使用してこの問題を解決する別のアプローチがあります。たとえば、次のコマンドを使用して、変数が829または845であるかどうかを確認できます。

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

変数にこれら2つの値のいずれかがある場合、結果はゼロになります。変数が範囲内にあるかどうかを確認するには、式は次のとおりです。

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

前の式では、変数が制限のいずれかである場合に備えて、(ゼロによる除算を管理するために)小さなプロビジョニングが必要です。以下のプログラムは、各グループの適切な儀式表現を組み立てます。その後、各値のチェックは、最大4つのSET / Aコマンド(グループごとに1つ)で実行されます。この方法は、FORループ内の各値を個別にテストするよりも高速であり、個々の要素ごとではなく、グループごとに1つの変数のみを使用します。

@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 に答える
1

決して完璧ではありませんが、実用的な出発点です。次のスクリプトをとして保存し、group.batで呼び出して、group 878878がどのグループに属しているかを確認します。

@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は、最初の引数が2番目の引数として渡されたリストに含まれているかどうかを確認します。

于 2012-07-02T21:59:17.320 に答える
1

バッチには、配列、リスト、オブジェクトなどの正式な複雑なデータ構造はありません。しかし、それらをエミュレートすることはできます。これは、質問のような形式でグループを定義する効率的なソリューションです。

@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

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 に答える