Acy Forsythe wrote:And what are the "" for?
Quotes are often used to enable support for special characters without the need to escape them with a ^. Special characters include & ^ < > |. The set "var=value" syntax eliminates the need to escape special characters, yet does not introduce the "" into the value. The "" don't do much good in this function however because the final
echo.%line% will fail and/or give unwanted results if
%line% contains special characters.
Acy Forsythe wrote:I understand that adding the second call expands the %~2 into the parameter passed to it.
And I can *guess* that the first call is expanding %%~%i% into %~2, but I guess what I'm not understanding is all of the %'s and what they are for.
Your "guess" is spot on. Why the many %'s are needed has to do with the peculiarities of the batch parser and the decision to write the function without using delayed expansion. Read the discussion of delayed expansion within the FOR help for an explanation of the issue accessing a variable that has been set within a FOR loop. People sometimes use CALL along with doubled up %% to avoid the use of delayed expansion. In this case we have quadrupled %%%% because we need two passes, one to access the iteration count, the 2nd to access the function parameter.
See
CALL me, or better avoid call for a discussion of the performance penalty of the CALL %%var%% technique.
Here is the function rewritten to use delayed expansion.
Code: Select all
:Format fmt str1 str2 ... -- outputs columns of strings right or left aligned
:: -- fmt [in] - format string specifying column width and alignment, i.e. "[-10][10][10]"
:$created 20060101 :$changed 20091130 :$categories Echo
:$source http://www.dostips.com
:: rewritten to use delayed expansion
setlocal enableDelayedExpansion
set "fmt=%~1"
set "line="
set "spac= "
set "i=1"
for /f "tokens=1,2 eol=[ delims=[" %%a in ('"echo.%fmt:]=&echo.%"') do (
set /a i+=1
call set "subst=%%~!i!!spac!%%~!i!"
if %%b0 GEQ 0 (set "subst=!subst:~0,%%b!") ELSE (set "subst=!subst:~%%b!")
set "line=!line!%%a!subst!"
)
echo.!line!
exit /b
On my machine this function is nearly 3 times faster than the original.
We can't completely elliminate the CALL within the loop because we need to access a different function parameter on each pass. There is no delayed expansion option for function parameters.
Besides using delayed expansion, I added
eol=[ to the FOR /F options, thereby eliminating the need to prepend strings with a . that later needed to be stripped again. Without either technique the function will have problems with strings that begin with a semicolon (the default EOL character). It is only a recent discovery that EOL can be disabled by setting it to match one of the delimiters. (
See the 3rd, 5th and 9th posts in this thread)
One other benefit of the rewrite is it now allows special characters in the replacement strings because the final ECHO is using delayed expansion. However the function still fails if there are special characters in the format string.
One detractor of this modified version is it now fails if there is a ^ or ! in either the format or replacement string because of added escape requirements needed while delayed expansion is enabled.
Dave Benham