Advertisement
Guest User

Arrays for CMD/BAT

a guest
Feb 21st, 2015
1,209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Batch 11.62 KB | None | 0 0
  1. @Echo Off
  2. SetLocal EnableDelayedExpansion
  3.  
  4. :: Небольшое демо
  5. Call :Array new Test "'random string','123','34',567,abcd,'TEST1',test2,'',qWerty"
  6. Echo View array:
  7. Call :Array echo Test
  8. Echo ==============
  9. Call :Array shuffle Test
  10. Echo View after shuffle:
  11. Call :Array echo Test
  12. Echo ==============
  13. Call :Array get Test 4 out
  14. Echo Element no.4:
  15. Echo [4] !out!
  16. Echo ==============
  17. Echo Search:
  18. Call :Array find Test "s" f
  19. Call :Array find Test "s" f out
  20. Echo Elements = [!out!]
  21. Echo ==============
  22. pause
  23.  
  24. :Array (action,name,data)
  25. :: Обработчик команды
  26. For %%A In (new,wipe,copy,add,delete,set,sort,shuffle,get,find,view,echo) Do (
  27.     If "%~1"=="%%A" (
  28.         Call :[]%%A %2 %3 %4 %5 &:: Передаём аргументы далее, исключая саму команду
  29.         Exit /B 0
  30.     )
  31. )
  32. :: Вывод справки если команда не указана или не существует
  33. :: Ага, мой английский ужасен.
  34. Echo. Arrays for CMD
  35. Echo. Inquisitor, 2011
  36. Echo. USAGE:    Call :Array ^<action^> ^<array name^> ^<data^>
  37. Echo. Actions:
  38. Echo.   new - Create array
  39. Echo.         Call :Array new A "'one','two','three'"
  40. Echo.   wipe    - Delete array
  41. Echo.         Call :Array wipe A
  42. Echo.   copy    - Create copy of array
  43. Echo.         Call :Array copy A B
  44. Echo.   add - Add element to existing array
  45. Echo.         Call :Array add A "four"
  46. Echo.         Call :Array add A "'some more','elements'"
  47. Echo.   delete  - Delete item from array
  48. Echo.         Call :Array delete A 2
  49. Echo.   set - Change the value of the item by its number in the index
  50. Echo.         Call :Array set A 1 "test"
  51. Echo.   sort    - Sort array
  52. Echo.         Call :Array sort A
  53. Echo.   shuffle - Shuffle array in random order
  54. Echo.         Call :Array shuffle A
  55. Echo.   get - Get the value of element to specified variable
  56. Echo.         use 'index' instead of number to obtain array element count
  57. Echo.         Call :Array get A 3 ^<variable name^>
  58. Echo.   find    - Find all elements with this value
  59. Echo.         if defined var name, returns array with element numbers
  60. Echo.         mode: s - regular, i - case insensitive, f - fuzzy
  61. Echo.         Call :Array find A "string" ^<mode^> ^<variable name^>
  62. Echo.   view    - Print the array elements
  63. Echo.         Call :Array view A
  64. Echo.   echo    - Print the array elements w/ index
  65. Echo.         Call :Array echo A
  66. Exit /B 2
  67.  
  68. :[]new (name,data)
  69. :: Проверки
  70. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  71. If "%~2"=="" (Echo Array data is empty&&Exit /B 1)
  72. If Defined $%~1[index] (Echo Array already exist&&Exit /B 1)
  73. Set "ArrayData=%~2"
  74. Set /A i=0
  75. :: Разбираем входящие данные и создаём элементы. Пустое значение всегда указывается как ''.
  76. :: Значение элемента всегда начинается с "=", этот трюк позволяет использовать пустые значения без проблем с неопределённой переменной
  77. For %%A In (%ArrayData:'=^"%) Do (
  78.     Set /A i+=1
  79.     Set "$%~1[!i!]==%%~A"
  80. )
  81. Set "$%~1[index]=!i!"
  82. Exit /B
  83.  
  84. :[]echo (name)
  85. :: Проверки
  86. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  87. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  88. :: Выводим массив в понятном человеку виде
  89. Echo.   %~1[]
  90. For /L %%A In (1,1,!$%~1[index]!) Do (
  91.     Echo [%%A]: "!$%~1[%%A]:~1!"
  92. )
  93. Exit /B
  94.  
  95. :[]view (name)
  96. :: Проверки
  97. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  98. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  99. :: Выводим массив без лишних свистоперделок, можно перенаправить в файл, например.
  100. For /L %%A In (1,1,!$%~1[index]!) Do (
  101.     Echo.!$%~1[%%A]:~1!
  102. )
  103. Exit /B
  104.  
  105. :[]wipe (name)
  106. :: Проверки
  107. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  108. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  109. :: Очищаем все элементы и индекс
  110. For /L %%A In (1,1,!$%~1[index]!) Do (
  111.     Set "$%~1[%%A]="
  112. )
  113. Set "$%~1[index]="
  114. Exit /B
  115.  
  116. :[]add (name,data)
  117. :: Проверки
  118. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  119. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  120. :: Добавляем значения в массив. Можно бы было слить с :[]new, там почти тот же код, но лень
  121. Set "ArrayData=%~2"
  122. Set i=!$%~1[index]!
  123. For %%A In (,%ArrayData:'=^"%) Do (
  124.     Set /A i+=1
  125.     Set "$%~1[!i!]==%%~A"
  126. )
  127. Set "$%~1[index]=!i!"
  128. Exit /B
  129.  
  130. :[]copy (name1,name2)
  131. :: Проверки
  132. If "%~1"=="" (Echo First name not specified&&Exit /B 1)
  133. If "%~2"=="" (Echo Second name not specified&&Exit /B 1)
  134. If Not Defined $%~1[index] (Echo Can't copy nonexistent array&&Exit /B 1)
  135. If Defined $%~2[index] (Echo Array already exist&&Exit /B 1)
  136. :: Полностью переносим содержимое массива в новый
  137. For /L %%A In (1,1,!$%~1[index]!) Do (
  138.     Set "$%~2[%%A]=!$%~1[%%A]!"
  139. )
  140. Set "$%~2[index]=!$%~1[index]!"
  141. Exit /B
  142.  
  143. :[]delete (name,element)
  144. :: Проверки
  145. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  146. If "%~2"=="" (Echo Element not specified&&Exit /B 1)
  147. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  148. If Not Defined $%~1[%~2] (Echo Element not found&&Exit /B 1)
  149. :: Делаем копию и удаляем оригинал
  150. Call :[]copy "%~1" "$copy_%~1"
  151. Call :[]wipe "%~1"&&Set "$%~1[index]=0"
  152. :: Добавляем в исходный массив все элементы, кроме указанного.
  153. :: Медленно, чёрт побери. Фактически это полная пересборка. Но по другому тяжело организовать удаление со сдвигом нумерации.
  154. :: Сокращение числа вызовов :[]add, как это реализовано в :[]shuffle, не приносит заметного прироста производительности
  155. For /L %%A In (1,1,!$$copy_%~1[index]!) Do (
  156.     If Not "%%A"=="%~2" Call :[]add "%~1" '!$$copy_%~1[%%A]:~1!'
  157. )
  158. :: Удаляем массив если в нём ничего не осталось и чистим за собой
  159. If "!$%~1[index]!"=="0" Set "$%~1[index]="
  160. Call:[]wipe "$copy_%~1"
  161. Exit /B
  162.  
  163. :[]set (name,element,data)
  164. :: Проверки
  165. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  166. If "%~2"=="" (Echo Element not specified&&Exit /B 1)
  167. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  168. If Not Defined $%~1[%~2] (Echo Element not found&&Exit /B 1)
  169. :: Устанавливаем новое значение.
  170. Set "ElementValue=%~3"
  171. :: Перестраховка
  172. Set "$%~1[%~2]==!ElementValue:'=!"
  173. Exit /B
  174.  
  175. :[]sort (name)
  176. :: Проверки
  177. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  178. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  179. :: Сбрасываем массив во временный файл. Без него никак, выхлоп функции нельзя передать через пайп
  180. Set tmpDump=%Temp%\a_%random%%random%.tmp
  181. Call :[]view "%~1">"%tmpDump%"
  182. :: Сортировка. Find служит для вывода не печатаемых в обычной ситуации пустых строк.
  183. Call :[]wipe "%~1"&&Set "$%~1[index]=0"
  184. For /F "eol= delims=] tokens=1,*" %%A In ('Sort "%tmpDump%"^|Find /V /N ""') Do (
  185.     Call :[]add "%~1" "'%%B'"
  186. )
  187. Del "%tmpDump%"
  188. Exit /B
  189.  
  190. :[]shuffle (name)
  191. :: Проверки
  192. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  193. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  194. :: Делаем копию, которая служит источником данных во время рандомной выборки
  195. Call :[]copy "%~1" "$shuffle_%~1"
  196. :: Удаляем исходный массив и заново наполняем его
  197. Call :[]wipe "%~1"&&Set "$%~1[index]=0"
  198. Set "rndSequence=,"&&Set i=0
  199. :rndseq :: Почему не цикл? Чтобы не играться с экранированием вложенных скобок, да и более читаемо
  200.     Echo !random!!random!>nul
  201.     Set /A rnd=1+!$$shuffle_%~1[index]!*%random%/32768
  202.     If "!rndSequence!"=="!rndSequence:,%rnd%,=!" (
  203.         Set rndSequence=!rndSequence!!rnd!,
  204.         Set /A i+=1
  205.     )
  206.     If !i! GEQ !$$shuffle_%~1[index]! (
  207.         Set "ArrayData="
  208.         :: Формируем строку для добавления
  209.         For %%A In (%rndSequence%) Do (
  210.             Call :StrLen ArrayData &:: Если данные превысили половину макс. размера переменной, добавляем в массив и чистим
  211.             Set ArrayData=!ArrayData!,'!$$shuffle_%~1[%%~A]:~1!'
  212.             If !ArrayData.strlen! GEQ 4096 (
  213.                 Call :[]add "%~1" "!ArrayData!"
  214.                 Set "ArrayData="
  215.             )
  216.         )
  217.         Call :[]add "%~1" "!ArrayData!" &:: Добавляем остаток в случае большого массива или все данные для маленького
  218.         Call :[]wipe "$shuffle_%~1"
  219.         Exit /B
  220.     )
  221. GoTo :rndseq
  222.  
  223. :[]get (name,element,out:variable)
  224. :: Проверки
  225. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  226. If "%~2"=="" (Echo Element not specified&&Exit /B 1)
  227. If "%~3"=="" (Echo Output name not specified&&Exit /B 1)
  228. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  229. If Not Defined $%~1[%~2] (Echo Element not found&&Exit /B 1)
  230. Set "%~3=!$%~1[%~2]:~1!"
  231. Exit /B
  232.  
  233. :[]find (name,search_string,mode,out:variable)
  234. :: Проверки
  235. If "%~1"=="" (Echo Name not specified&&Exit /B 1)
  236. If Not Defined $%~1[index] (Echo This array not existed&&Exit /B 1)
  237. If "%~2"=="" (Echo Search string is empty&&Exit /B 1)
  238. If "%~3"=="" (Echo Search mode not specified&&Exit /B 1)
  239. Set SearchMode=/i/s/f/
  240. If "!SearchMode!"=="!SearchMode:/%~3/=!" (Echo Invalid search mode, see help&&Exit /B 1)
  241. :: Сбрасываем массив во временный файл. При нескольких тысячах элементов есть разница,
  242. :: вызывать find на каждую строку или лишь единожды
  243. Set tmpDump=%Temp%\a_%random%%random%.tmp
  244. Call :[]view "%~1">>"%tmpDump%"
  245. Set "SearchResult="
  246. :: Обычный поиск, нужно точное совпадение, вплоть до регистра символов.
  247. If "%~3"=="s" (
  248.     For /F "tokens=1 delims=:" %%A In ('Findstr /XNC:"%~2" "%tmpDump%"') Do (Set SearchResult=!SearchResult! %%A)
  249. )
  250. :: Обычный, но независимо от регистра
  251. If "%~3"=="i" (
  252.     For /F "tokens=1 delims=:" %%A In ('Findstr /XINC:"%~2" "%tmpDump%"') Do (Set SearchResult=!SearchResult! %%A)
  253. )
  254. :: Нечёткий поиск, регистронезависим и находит все включения строки
  255. If "%~3"=="f" (
  256.     For /F "tokens=1 delims=:" %%A In ('Findstr /INC:"%~2" "%tmpDump%"') Do (Set SearchResult=!SearchResult! %%A)
  257. )
  258. :: Если указано имя переменной для вывода, выдаём последовательность номеров туда, иначе - просто показываем строки и номера.
  259. If Not "%~4"=="" If Defined SearchResult (Set "%~4=!SearchResult:~1!") Else (Set "%~4=")
  260. If "%~4"=="" If Defined SearchResult (
  261.     Echo.   %~1[], searched for "%~2"
  262.     For %%A In (!SearchResult:~1!) Do (Echo [%%A]:  "!$%~1[%%A]:~1!")
  263. ) Else (
  264.     Echo Not found
  265. )
  266. Del "%tmpDump%"
  267. Exit /B
  268.  
  269. :StrLen (name,out:name.strlen]
  270. :: Получение размера строки по имени переменной
  271. Set StrLen.S=A!%~1!
  272. Set StrLen=0
  273. For /L %%P In (12,-1,0) Do (
  274.     Set /A "StrLen|=1<<%%P"
  275.     For %%I In (!StrLen!) Do If "!StrLen.S:~%%I,1!"=="" Set /A "StrLen&=~1<<%%P"
  276. )
  277. Set "%~1.strlen=!StrLen!"
  278. Exit /B
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement