Я возился с пакетной службой и пишу код, который перебирает файлы в каталоге и добавляет последние четыре символа имени файла в массив. Проблема в том, что в моем массиве есть дубликаты. Есть ли способ добавить значение в массив, только если оно еще не существует?
@echo off
setlocal enableDelayedExpansion
set i=0
for %%f in (*00.DIF) do (
set fname=%%~nf
set year=!fname:~-4!
::echo !year!
set Obj[!i!].name=!year!
set /a i=!i!+1
)
set lastindex=!i!
for /L %%f in (0,1,!lastindex!) do (
echo !Obj[%%f].name!
)
set Obj[ | findstr /e "=!year! && ( echo !year! already exists ) || ( echo unique !year! )
. замените команды echo
нужными вам функциями. ВНИМАНИЕ: замените ::
на REM
. ::
— это (недопустимая) метка, которая вызывает неожиданное поведение (например, пропуск строк). @Tim: код легко читается. Не существует «лучшего» языка. Часто «лучшее» — это то, к чему вы больше всего привыкли (если оно справляется со своей задачей).
@TimRoberts — Batch — это язык сценариев. То, что вы не можете этого понять, не означает, что это непонятно (хотя, кстати, забавно, что вы рекомендуете Perl и Ruby). Каждую из этих строк может легко понять человек, обладающий хотя бы поверхностным знанием языка.
(или ... | findstr /elc:"].name=!year!" ...
, если .name
намекает, что могут быть и другие obj[...].<anythingElse>
)
Я заранее извиняюсь за свое невежество, код, который вы видите выше, создан после дневного поиска в Google. @Стефан, я пытаюсь понять, как применить твой код, и на данный момент мне это удалось, но это не отражает ничего ценного. Он просто повторяет «Obj[0].name=K900» снова и снова. К900 — одно из «годовых» значений.
Очень странно, что все ваши имена файлов заканчиваются на *2000.DIF
, *1900.DIF
, *1800.DIF
, *1700.DIF
и т. д. Подождите, я только что увидел ваш комментарий выше; в твоих годах есть символы алфавита!
Как уже отмечалось, внутри оператора блока (a parenthesised series of statements)
следует использовать операторы REM
, а не форму примечания с разорванной меткой (:: comment
), поскольку метки завершают блоки, сбивая с толку cmd
. ::
— это неработающая метка, потому что до ::
нельзя добраться с помощью goto
, но тем не менее это метка.
Используйте set "var=value"
для установки строковых значений — это позволяет избежать проблем, вызванных конечными пробелами. Не назначайте "
, обратную косую черту или пробел. Создавайте пути из элементов — как ни странно, это, вероятно, облегчит процесс. Используйте set /a var=value
, чтобы установить числовые значения.
Я предпочитаю избегать ADFNPSTXZ (в любом случае) в качестве метапеременных (переменных управления циклом).
ADFNPSTXZ также являются модификаторами метапеременных, что может привести к трудно обнаруживаемым ошибкам.
(См. for/f
в приглашении к документации)
Синтаксис !var!
требуется только для доступа к измененному значению var
, где var
варьируется внутри блока кода (последовательность команд в скобках).
Следовательно, переписанный код:
@ECHO OFF
setlocal enableDelayedExpansion
set /A i=0
SET "chosen = "
REM for %%e in (*00.DIF) do (
for %%e in (1234 0011 4567 7890 0011 4183) do (
set fname=%%~ne
set year=!fname:~-4!
REM echo !year!
set Obj[!i!].name=!year!
set /a i+=1
SET "unaltered=Y"
FOR %%y IN (!chosen!) DO IF DEFINED unaltered IF "%%y"= = "!year!" (
SET "unaltered = "
set /a i-=1
set "Obj[!i!].name = "
)
IF DEFINED unaltered SET "chosen=!year! !chosen!"
)
set /a lastindex=i-1
for /L %%e in (0,1,%lastindex%) do (
echo !Obj[%%e].name!
)
GOTO :EOF
Новая переменная chosen
не имеет значения.
Я заменил ваш первый цикл for
циклом, который просто обрабатывает серию чисел в целях тестирования. Я также изменил metavariable
с f
на e
.
Используйте более современный синтаксис для увеличения i
. см. set/?
из подсказки или бесконечные элементы SO для docco.
Новый цикл %%y
для поиска chosen
ранее присвоенных значений. Обратите внимание на использование unaltered
в качестве логического значения: оно либо определено как Y
, либо не определено. Если он определен, просто отмените приращение i
и удалите назначенное строковое значение «массив». Использование логического значения
Затем, если значение в year
новое, unaltered
определяется и новое значение year
добавляется к списку значений в chosen
.
После обработки всего списка lastindex
устанавливается в i
- 1, поскольку i
указывает на следующий элемент, который необходимо заполнить.
--- редактировать -----
Перекаффиенировав, воспользовавшись идеей Стефана findstr
...
@ECHO OFF
setlocal enableDelayedExpansion
set /A i=0
SET "chosen = "
REM for %%e in (*00.DIF) do (
for %%e in (1234 0011 4183 4567 7890 0011 7890 7890 7890 4183) do (
set fname=%%~ne
set year=!fname:~-4!
REM echo !year!
ECHO !year!|FINDSTR ": !chosen!" >NUL
IF ERRORLEVEL 1 (
set Obj[!i!].name=!year!
set /a i+=1
SET "chosen=!year! !chosen!"
)
)
set /a lastindex=i-1
for /L %%e in (0,1,%lastindex%) do (
echo !Obj[%%e].name!
)
GOTO :EOF
Здесь, если year
нет в строке chosen
, то findstr
установит errorlevel
в 1
; если да, то errorlevel
будет установлено на 0
.
findstr
по умолчанию находит любую строку, разделенную пробелом, но ему не нравятся пустые строки, поэтому в список добавляется двоеточие как пустышка; двоеточие в имени файла невозможно.
Только если yesr
отсутствует в списке, он будет добавлен.
Нам не нужен фактический вывод findstr
, просто он устанавливает errorlevel
, поэтому вывод >nul
отправляется в никуда.
Это похоже на сон! Спасибо! Что именно делает (1234 0011 4567 7890 0011 4183)? Также спасибо за подробности. Я буду перечитывать это снова и снова, пока это не обретет смысл, лол!
Эта строка просто устанавливает %%e
в эти строки последовательно в целях тестирования, чтобы мне не приходилось создавать *00.dif
файлы для тестирования процедуры. Просто удалите эту строку и снимите REMark с (измененного) оригинала, чтобы вместо этого обрабатывать имена файлов.
Вы не указали, важен ли порядок элементов массива. Если нет, то есть очень простой способ решить вашу проблему: вместо числового индекса используйте в качестве индекса значение!
@echo off
setlocal enableDelayedExpansion
for %%f in (*00.DIF) do (
set fname=%%~nf
set year=!fname:~-4!
REM echo !year!
set Obj[!year!].name=!year!
)
REM Show array elements
for /F %%a in ('set Obj[') do (
echo %%a
)
Поскольку не может быть более одного элемента с одним и тем же индексом, не имеет значения, определен ли один и тот же элемент более одного раза. В конце концов, существует только один элемент с таким индексом.
PS. Почему вы назвали Obj[#].name
массив? Это очень необычно, потому что часть «имя» не отображается в значениях. ИМХО, имя могло бы быть и получше Year[#]
Будем честны. Даже если вы сможете заставить эту работу работать, ее никогда не удастся поддерживать. Линии выглядят как случайный шум, и когда вы вернетесь к ним шесть недель спустя, вы их не узнаете. Как только вы дойдете до этого момента, вам следует использовать язык сценариев: Python, Perl, Ruby, LUA. или даже бить.