2014-01-16 1 views
0

мне нужно решение следующей задачи в пакетном файле,переключатель в случае с данным пользователем элементов массива - партия

Пользователь дает вход с пробелом между каждым следующим входным элементом.

Входы необходимо хранить в массиве как элементы массива.

Ввод должен приниматься как имя случая, и конкретный случай должен быть выполнен. Следовательно, каждый случай с именем элемента массива должен быть выполнен

Размер массива не задан. Это изменяется, поскольку пользователь может дать любое количество входов

алгоритм должен быть, как это, входные номера

пользователей являются 1 2 4 6, которые хранятся в массиве с [I]

a[i] = {1,2,4,6} 



for i = 1 to len(a[i]) 

CALL :CASE_%a[i]% # jump to :CASE_1, :CASE_2, etc. 

:CASE_1 
Echo “am in case1” 
:: go to the for loop 

:CASE_2 
Echo “am in case2” 
:: go to the for loop 

:CASE_3 
Echo “am in case3” 
:: go to the for loop 

:CASE_4 
Echo “am in case4” 
:: go to the for loop 

:CASE_5 
Echo “am in case5” 
:: go to the for loop 

:CASE_6 
Echo “am in case6” 
:: go to the for loop 

:CASE_7 
Echo “am in case7” 
:: go to the for loop 

:CASE_8 
Echo “am in case8” 
:: go to the for loop 



End for 

Case_1, Case_2, Case_4, Case_6 необходимо выполнить только в качестве ввода 1 2 4 6.

Возможно ли это в пакетном файле?

ответ

0

Я разделить проблему на три части. Ввод данных в массив, получение данных из массива и имитация команды case, отсутствующей в партии.

@echo off 
    setlocal enableextensions enabledelayedexpansion 

    set /p "data=Input data:" 

Давайте предположим, что пользователь вводит только числовые значения (чтобы избежать все необходимые проверки и только смотреть на проблему), как указано, разделенных пробелами. Поместите их в «массив». Нет, массивы не присутствуют в пакетных сценариях, но могут быть смоделированы, давая переменным собственные имена.

set "arrayLength=0" 
for %%e in (%data%) do (
    set /a "arrayLength+=1" 
    set "a[!arrayLength!]=%%e" 
) 

Это перебирает входные данные, и для каждого элемента, счетчик увеличивается на единицу, и переменный с именем a[ + counter value + ] создаются. Нет, это не массив, а просто переменная с именем, позволяющая нам имитировать массив sintax. По мере того как счетчик (arrayLength) является неоспоримым изменен внутри цикла, задержка расширения требуется, чтобы прочитать эту измененную величину, и синтаксис для изменения переменного считываются из %var% к !var!

Теперь данные находятся в «массиве». Мы собираемся перебирать «массив», проверяя его содержимое.

for /l %%i in (1 1 %arrayLength%) do (
    echo element %%i is : !a[%%i]! 
) 

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

Как проверить значения «массива»?

echo Test IF 
for /l %%i in (1 1 %arrayLength%) do (
    if "!a[%%i]!"=="1" (
     echo Case 1 
    ) else if "!a[%%i]!"=="2" (
     echo Case 2 
    ) else if "!a[%%i]!"=="3" (
     echo Case 3 
    ) else if "!a[%%i]!"=="4" (
     echo Case 4 
    ) else if "!a[%%i]!"=="5" (
     echo Case 5 
    ) else if "!a[%%i]!"=="6" (
     echo Case 6 
    ) else (
     echo NO CASE 
    ) 
) 

Это перебирает в «массиве» и использует каскадную IF синтаксиса для проверки допустимых значений. Это легко кодировать, быстро, но не наиболее удобно поддерживать, если есть частые изменения в случаях.

Альтернативой каскаду IF является использование подпрограмм. В зависимости от значения элемента «массив» вызовите одну метку или другую. Просто назовите этикетки адекватно.

Затем вы можете проверить, существует ли метка/подпрограмма, а затем вызвать ее.

Или вы можете позвонить напрямую без предварительной проверки и проверки ошибок в вызове, которые указывают, что метка не существует.

Или можно определить таблицу подпрограмм.

Для образца, если следующие метки определены

:case[1] 
    echo Case 1 
    goto :eof 
:case[2] 
    echo Case 2 
    goto :eof 
:case[3] 
    echo Case 3 
    goto :eof 
:case[4] 
    echo Case 4 
    goto :eof 
:case[5] 
    echo Case 5 
    goto :eof 
:case[6] 
    echo Case 6 
    goto :eof 

Кодекса называть это подпрограммой с предыдущей проверкой существования в пакетном файле (%~f0 является текущим командным файлом с полным путем) может быть

rem Use labels in batch with previous test of existence 
for /l %%i in (1 1 %arrayLength%) do (
    findstr /l /c:":case[!a[%%i]!]" "%~f0" > nul 2>nul 
    if not errorlevel 1 (
     call :case[!a[%%i]!] 
    ) else (
     echo NO CASE 
    ) 
) 

findstr Это использует для чтения текущих пакетного поиска файлов для :case[n] этикетки. Без ошибок метка была найдена и вызов выполнен. Но чтение командного файла для проверки существования метки не является самой быстрой операцией.

Чтобы не проверять наличие этикетки и непосредственно сделать вызов, этот код может быть использован

rem Use labels in batch without check 
for /l %%i in (1 1 %arrayLength%) do (
    ver>nul 
    call :case[!a[%%i]!] 2>nul 
    if errorlevel 1 echo NO CASE 
) 

«вер> nul` линия symply обеспечивает Равно очищаются перед вызовом подпрограммы. Вызов выполняется, и проверяется уровень ошибок. Но нет способа узнать, исходит ли уровень ошибок из команды вызова или изнутри вызываемой подпрограммы.

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

set "func[1]=:case[1]" 
set "func[2]=:case[2]" 
set "func[3]=:case[3]" 
set "func[4]=:case[4]" 
set "func[5]=:case[5]" 
set "func[6]=:case[6]" 

Следующий код может вызвать adecuated подпрограмму, cheching если функция стоимости определяется

for /l %%i in (1 1 %arrayLength%) do (
    for %%v in (!a[%%i]!) do if defined func[%%v] (
     call !func[%%v]! 
    ) else (
     echo NO CASE 
    ) 
) 

Внутреннее значение необходимо для получения ссылки на значение внутри «массива», которое будет использоваться для доступа к имени функции внутри массива func.

И ..... что-нибудь лучшее, что можно было бы себе представить.


В конце концов, какой код следует использовать? Что работает для вас. Все зависит от реальной проблемы.

Каскад IF является быстрым и легким, но для проблемы с частыми меняющимися случаями сложнее поддерживать.

Findstr занимает много времени.

Звонок без проверки может быть настоящим nigntmare.

Таблица функций находится посередине. Не так быстро, как наличие всего кода в блоке, как в решении IF, но быстрее, чем findstr, проверяя определение подпрограммы. Это не сложно скомпоновать, но для небольших проблем нетрудно.

Для простых случаев нужны только конструкции IF. Для сложных проблем, если код длинный, а случаи необходимо изменить, добавить, ... таблица функций упрощает работу.

Таким образом, это может привести к

@echo off 
    setlocal enableextensions enabledelayedexpansion 

    set /p "data=Input data:" 

    set "arrayLength=0" 
    for %%e in (%data%) do (
     set /a "arrayLength+=1" 
     set "a[!arrayLength!]=%%e" 
    ) 

    rem func[ allowedValue ] = label to call 
    set "func[1]=:handleCase_1" 
    set "func[2]=:handleCase_2" 
    set "func[3]=:handleCase_3" 
    set "func[4]=:handleCase_4" 
    set "func[5]=:handleCase_5" 
    set "func[6]=:handleCase_6" 

    for /l %%i in (1 1 %arrayLength%) do (
     for %%v in (!a[%%i]!) do if defined func[%%v] (
      call !func[%%v]! 
     ) else (
      echo NO CASE 
     ) 
    ) 

    for /l %%i in (1 1 %arrayLength%) do (
     if "!a[%%i]!"=="1" (
      echo Case 1 
      rem Or, we can 
      rem call :handleCase_1 
     ) else if "!a[%%i]!"=="2" (
      echo Case 2 
     ) else if "!a[%%i]!"=="3" (
      echo Case 3 
     ) else if "!a[%%i]!"=="4" (
      echo Case 4 
     ) else if "!a[%%i]!"=="5" (
      echo Case 5 
     ) else if "!a[%%i]!"=="6" (
      echo Case 6 
     ) else (
      echo NO CASE 
     ) 
    ) 

    endlocal 
    exit /b  

:handleCase_1 
    echo Case 1 
    goto :eof 
:handleCase_2 
    echo Case 2 
    goto :eof 
:handleCase_3 
    echo Case 3 
    goto :eof 
:handleCase_4 
    echo Case 4 
    goto :eof 
:handleCase_5 
    echo Case 5 
    goto :eof 
:handleCase_6 
    echo Case 6 
    goto :eof 
+0

Большое спасибо. Первые четыре части кода, которые вы дали, отлично работали. У меня есть еще одна работа, которая должна быть сделана там в четвертой части. После echo case1 необходимо сделать вызов (скажем, goto func1), значение func1 определено после 4-й части. этот goto func1 должен присутствовать в каждом случае. Тем не менее программа должна работать нормально. Это возможно? Заранее спасибо. Следовательно, func1 следует вызывать из if!! A [%% i]! "==" 1 "и если"! A [%% i]! "==" 3 "и если"! A [%% i] ! "==" 5 " , если в качестве входного сигнала указано значение 1 3 5. – KeeKu

+0

@ user3173444: 'func1' будет использоваться из более чем одного места, затем закодировать его как подпрограмму и вызвать его с помощью' call: func1'. Пятый и шестой разделы кода в ответе показывают, как его определить. Тогда, в структуре if у вас будет 'if '! A [%% i]!" == "1" ( .... что здесь и называть: func1 ) else if "! A [%% i]! "==" 2 "( .... ) else if"! a [%% i]! "==" 3 "( .... что здесь и называть: func1 ) else ... ' –

+0

Да, это сработало. Благодарю. – KeeKu

0

Пакет Windows не имеет истинной поддержки массивов, но их можно эмулировать с помощью умных имен переменных. Например, a[1] и a.len являются обычными именами переменных, сценарий не знает ни одного объекта с именем a. Вместо этого я использую точечную нотацию: a.1, a.2, ... a.len. Вы свободны развивать свой собственный стиль.

@echo off 
setlocal enableDelayedExpansion 

set a[1]=1 
set a[2]=2 
set a[3]=4 
set a[4]=6 
set a.len=4 

:: You can also do multiple numerical assignments on one line using SET /A 
:: set /a "a[1]=1, a[2]=2, a[3]=4, a[4]=6, a.len=4" 

for /l %%i in (1 1 %a.len%) do (
    call :CASE_!a[%%i]! 
) 

:: You must exit the script so you don't fall into the subroutines after the loop finishes 
exit /b 


:CASE_1 
Echo am in case1 
exit /b 

:CASE_2 
Echo am in case2 
exit /b 

:CASE_3 
Echo am in case3 
exit /b 

:CASE_4 
Echo am in case4 
exit /b 

:CASE_5 
Echo am in case5 
exit /b 

:CASE_6 
Echo am in case6 
exit /b 

:CASE_7 
Echo am in case7 
exit /b 

:CASE_8 
Echo am in case8 
exit /b 
0

Я рассмотрел вашу проблему и, на мой взгляд, не требует использования массива. Я думаю, вы говорите о списке . Таким образом, поставленная задача может быть решена с помощью списка таким образом:

@echo off 

rem The user gives the input with a space in between every next input element. 
set /P input= 

rem The input has to be taken as the case name and the particular case need to be executed. 
rem Hence every case with the name of the array element need to be executed. 
for %%i in (%input%) do call :CASE_%%i 
goto :EOF 

:CASE_1 
Echo am in case1 
exit /B 

:CASE_2 
Echo am in case2 
exit /B 

:CASE_3 
Echo am in case3 
exit /B 

:CASE_4 
Echo am in case4 
exit /B 

:CASE_5 
Echo am in case5 
exit /B 

:CASE_6 
Echo am in case6 
exit /B 

Например:

C:\> test 
1 2 4 6 
am in case1 
am in case2 
am in case4 
am in case6 

Любое решение, которое заставил использовать ненужную массив будет сложнее .. .

Смежные вопросы