バッチファイルでProject Euler(61)

部分文字列

@echo off

setlocal
set s=1234567890
echo %s:~3%

こうすると、

4567890

と表示されます。しかし、任意の場所からの部分文字列を取るにはどうしたらいいでしょう。例えば、n = 3としたときに、nを使って部分文字列を取りたいです。

set /a n = 3
echo set sub=%%s:~%n%%%

とすると、echo以降が前から解釈されて、%%は%になり、%n%は3に置き換えられて、結局、

set sub=%s:~3%

と表示されます。ここからの連想で、

call set sub=%%s:~%n%%%

とすると、上の

set sub=%s:~3%

が実行されて、

4567890

となります。
これを応用して、文字列の長さを数えるのを速くしました。

@echo off

setlocal enabledelayedexpansion
set s=1234567890
for /L %%k in (1, 1, 5) do set s=!s!!s!
echo %time%
call :length %s%
echo %ERRORLEVEL%
echo %time%
call :length2 %s%
echo %ERRORLEVEL%
echo %time%
exit /b 0

:length
    setlocal
    if "%1" == "" exit /b 0
    set s=%1
    call :length %s:~1%
    set /a l = %ERRORLEVEL% + 1
    exit /b %l%

:length2
    setlocal
    if "%1" == "" exit /b 0
    set s=%1
    if "%2" == "" (
        call :length2 %s:~1% 2
        set /a l = !ERRORLEVEL! + 1
        exit /b !l!
    )
    call set sub=%%s:~%2%%
    if "%sub%" == "" (
        if %2 == 1 exit /b 1
        set /a l = %2 / 2
        call :length2 %1 !l!
        exit /b !ERRORLEVEL!
    ) else (
        set /a l = %2 * 2
        call :length2 %sub% !l!
        set /a l2 = %2 + !ERRORLEVEL!
        exit /b !l2!
    )