1

Тема: CMD/BAT: повторить строку несколько раз

Самая простая реализация алгоритма - (N - 1) раз склеить исходную строку с самой собой, чтобы получить новую строку содержащую N копий исходной (сложность алгоритма - O(n) = n). Однако этот алгоритм простой и неоптимальный с точки зрения скорости выполнения, существует более оптимальный, хотя и чуть более сложный алгоритм. Суть его -- удвоение строки. То есть сложность алгоритма порядка O(n) = log2(n). Давайте рассмотрим его подробнее:

Дано:
S - строка
N - умножитель, то есть сколько раз строку S повторить в результирующей строке

// Только непустые строки и не менее одного раза
if N <= 0 or S == ''
    return ''
end if

// Инициализация -- вычисление длины исходной строки
R = S
K = strlen(R)

// Инициализация -- счетчики
L = 1
N = N - 1

// Повторять пока счетчик не обнулится
while N <= 0
    // Остаток -- найти оставшуюся подстроку, добавить к результирующей и завершить
    if N <= L then
        M = N * K
        Q = substr(R, -M)
        R = R + Q
        break
    end if

    // Удвоение строки
    N = N - L
    R = R + R
end while

return R

Хотя язык и средства обработки строк не дотягивают до возможностей полноценного языка высокого уровня, тем не менее я озадачился -- а можно ли в пакетных скриптах реализовать этот алгоритм. Оказывается можно. Хотя возникла небольшая сложность, но и она была преодолена. Необходимое замечание - я не видел, чтобы этот алгоритм был часто востребован в пакетных скриптах, меня больше интересовала сама возможность реализации. Если кому-то это может пригодиться, я буду рад.
CMD/BAT: Repeat a string multiple times

:: Повторить MULTIPLIER раз строку INPUT 
::
:: @usage  call :str_repeat NAME MULTIPLIER INPUT
::
:: @param  name    имя переменной для сохранения результата
:: @param  number  количество раз
:: @param  string  входная строка
:str_repeat
setlocal enabledelayedexpansion

set R=
set N=

set /a N=%~2 2>nul

if not defined N goto str_repeat_break
if %N% leq 0 goto str_repeat_break

set R=%~3

if not defined R goto str_repeat_break

call :str_len K "%R%"

set /a L=1
set /a N=%N%-1

:str_repeat_continue
if %N% leq 0 goto str_repeat_break

if %N% leq %L% (
    set /a M=%N% * %K%
    call :str_repeat_part
    set R=%R%!Q!
    goto str_repeat_break
)

set /a N=%N% - %L%
set R=%R%%R%
set /a L*=2
goto str_repeat_continue

:str_repeat_break
endlocal && set %~1=%R%
exit /b 0

:str_repeat_part
set Q=!R:~-%M%!
goto :EOF
( 2 * b ) || ! ( 2 * b )