Продолжение. Начало здесь (копия)
Распишу алгоритм, реализованный в функции:
1. Устанавливаем режимы работы:
SetLocal EnableExtensions EnableDelayedExpansion
Справка по команде Копия в PDF
2. Устанавливаем начальные переменные в функции:
Set Out=%~0
Записываем в локальную переменную имя функции (%~0
). Зачем? А спросите у дизайнеров языка CMD, он ебанутый, и без этой фишки вывод данных из функции не сработает.
Set "param=%~1"
Записываем первый и единственный параметр переданный функции (%~1
), т.е. строку, в локальную переменную param
.
Set "str=A!param!"
Добавляем символ A
к строке param
с начала строки, сохраняем результат в локальную переменную str
. На самом деле, можно добавить любой печатный латинский символ. Пусть будет A
.
Set "len=0"
Счетчик длины устанавливаем в ноль.
3. Запускаем основной цикл:
for /l %%a in (30,-1,0) do ( [см. далее] )
Второй параметр цикла (-1
) означает, что цикл пойдет в обратном порядке, от 30
до 0
.
4. Внутри цикла:
4.1. set /a "len|=1<<%%a"
Производится битовый сдвиг переменной цикла (%%a
), т.е. к единице (двоичной) добавляется %%a
нолей (двоичных).
4.2. Над полученным числом производится операция побитового ИЛИ (|
), результат записывается в переменную len
.
4.3. Запускается второй (внутренний) цикл, количество итераций которого проводится по полученной ранее длине (len
):
for %%b in (!len!) do [...]
4.3.1. if "!str:~%%b,1!"==""
Внутри второго цикла, если мы нашли пустой символ на позиции, которую указывает счетчик (%%b
), проводим битовые операции над длиной:
4.3.2. set /a "len&=~1<<%%a"
4.3.2.1. Сначала проводится битовый сдвиг с единицей на %%a
разрядов (нолей)
4.3.2.2. Полученные биты инвертируются (~
) т.е., например, если полученное значение было равно 1000
(в двоичной системе счисления), то после операции ~
оно превращается в 0111
.
4.3.2.3. Последней производится операция побитового И (&
) и значение присваивается переменной len
.
5. Функция возвращает результат:
endlocal & set %Out:~1%=%len%
Функция целиком:
::Start Strlen function :Strlen SetLocal EnableExtensions EnableDelayedExpansion Set Out=%~0 Set "param=%~1" Set "str=A!param!" echo %str% Set "len=0" for /l %%a in (30,-1,0) do ( set /a "len|=1<<%%a" for %%b in (!len!) do if "!str:~%%b,1!"=="" set /a "len&=~1<<%%a" ) endlocal & set %Out:~1%=%len% exit /b 0
Сделал разбор алгоритма по шагам, при меньшем числе итераций (установил в основном цикле первый параметр равным 4
и строку для измерения длины сделал 10 символов — 0123456789
). Все свел в таблицу: