1

Note: The file Default.txt contains one line with these three characters:1:X

    @echo off
    set r=0
    :: For loop retrieves lines of text from the file Default.txt 
    FOR /F "tokens=1,2 delims=:" %%a IN (Default.txt) DO (
    :: Each line is saved to a different variable.
    set _%%a=%%b
    set n=%%a
    )
    set ln=1
    setlocal enabledelayedexpansion
    :process
    :: This loop processes all the lines in the text file.
    set r=0
    if "%n%" GTR "0" (
    :len
    :: This loop determines the length of each string.
    if not "!_%ln%:~%r%,1!"=="" (
    set /a r=%r%+1
    goto len
    )
    :space
    :: This loop adds spaces to each string so they will all be 39 characters in length.
    if "%r%" LEQ "39" (
    :: Note that there is a mandatory space at the end of the following line.
    set _%ln%=!_%ln%! 
    set /a r=%r%+1
    goto space
    )
    set /a n-=1
    set /a ln+=1
    goto process
    ) else (
    endlocal
    set _1=%_1%
    )
    echo %_1%]
    pause >nul

When the script is run however, instead of adding 38 spaces, it only adds 3. By turning echo back on, I found the exact point where it exits the :space loop.

    C:\>if "1" LEQ "39" (
    set _1=!_1!
     set /a r=1+1
     goto space
    )

    C:\>if "2" LEQ "39" (
    set _1=!_1!
     set /a r=2+1
     goto space
    )

    C:\>if "3" LEQ "39" (
    set _1=!_1!
     set /a r=3+1
     goto space
    )

Up to this point, everything is working as it should. Suddenly:

    C:\>if "4" LEQ "39" (
    set _1=!_1!
     set /a r=4+1
     goto space
    )

For some reason, 4 is suddenly greater than 39, and it moves on to the next section instead of incrementing the variable and looping again like it should.

    C:\>set /a n-=1

    C:\>set /a ln+=1

    C:\>goto process

And the program moves on and only 3 spaces are ever added to the variable. I have no idea what the problem is and would be grateful for any insight.

Sketch Turner
  • 55
  • 1
  • 6

3 Answers3

1
  C:\>if 4 LEQ 39 (
set _1=!_1!
 set /a r=4+1
 goto space
)  

Remove quotations and try that should work , quotes are normally used with strings.

prudviraj
  • 3,634
  • 2
  • 16
  • 22
  • Just to add some clarification - because quotes are being used, bash evaluates the strings lexicographically (similar to alphabetically), instead of numerically. In the same way that "A" < "B", "1" < "2", or when you have multiple characters, "aaaa" < "bbbb" and "11" < "20". When you have different lengths, it still evaluates alphabetically, so "111" < "20". – camdroid Jul 28 '15 at 15:31
1

When comparing numerics, don't enclose them in quotation marks.

command: if "4" leq "39" echo hi
output: (empty line)

command: if 4 leq 39 echo hi
output: hi

The reason for that is that "4" is alphabetically after "39", so "4 is greater than "3. When comparing using quotation marks, the comparison is alphabetic, not numeric as you intended.

You've got a few other problems with your script. Don't put labels within parenthetical code blocks. You need to find some other place to put :len and :space outside of the if statement where they currently live. Strictly speaking, :: is also label named :, not a substitute for rem. When using :: as a comment, avoid using it within parenthetical code blocks as well. Use rem instead. Also, indent your code to make it easier to ensure you've got the same number of ( as ). Let me ask you: which is more readable?

option 1:

...
:space
:: This loop adds spaces to each string so they will all be 39 characters in length.
if "%r%" LEQ "39" (
:: Note that there is a mandatory space at the end of the following line.
set _%ln%=!_%ln%! 
set /a r=%r%+1
goto space
)
set /a n-=1
set /a ln+=1
goto process
) else (
endlocal
set _1=%_1%
)
echo %_1%]
pause >nul

The else is a continuation of the if statement above it, right? Wrong! Properly indented, you'd see that it's part of an if statement much higher in the script.

option 2:

    rem This loop adds spaces to each string so they will all be 39 characters in length.

    if "%r%" LEQ "39" (
        rem Note that there is a mandatory space at the end of the following line.
        set _%ln%=!_%ln%! 
        set /a r=%r%+1
        goto space
    )

    set /a n-=1
    set /a ln+=1
    goto process

) else (
    endlocal
    set _1=%_1%
)
echo %_1%]
pause >nul

I'll never understand why some people insist on left-justifying every line of code they write. It only makes things much more difficult to troubleshoot.


You know, there are more efficient ways to repeat characters. Rather than looping, you could do variable substring extraction.

set "spaces=                                                  "
set "39spaces=%spaces:~-39%"

If you want to get the length of a string, the fastest way I've found to do that is based on jeb's answer here:

:length <return_var> <string>
setlocal enabledelayedexpansion
if "%~2"=="" (set ret=0) else set ret=1
set "tmpstr=%~2"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
    if not "!tmpstr:~%%I,1!"=="" (
        set /a ret += %%I
        set "tmpstr=!tmpstr:~%%I!"
    )
)
endlocal & set "%~1=%ret%"
goto :EOF

Example usage:

command: call :length len "The quick brown fox"
command: echo %len%
output: 19

Even if you're getting the length of a 2000 character line, that loop still counts the length in only 13 iterations, rather than potentially thousands.

Community
  • 1
  • 1
rojo
  • 24,000
  • 5
  • 55
  • 101
0

Prudviraj's answer answers why your original code doesn't work, but for an easier way of padding a string to 39 characters, you could try:

Make39.bat

@echo off
    setlocal
    set "R=%1"
    set "R=%R%                                       "   REM append 39 spaces
    set "R=%R:~,39%"                                     REM take first 39 characters
    echo :123456789012345678901234567890123456789:
    echo :%R%:

which works as follows:

S:\>make39 abc
:123456789012345678901234567890123456789:
:abc                                    :

S:\>make39 "Quite a long string"
:123456789012345678901234567890123456789:
:Quite a long string                    :

Your comments seem to imply no string will initially be longer than 39 characters; you would have to get more inventive if this were possible (I would probably take the first 39 characters of the original R and see if that and R differ: if they did, the original would have been longer, so there would be no need to add padding).

Community
  • 1
  • 1
TripeHound
  • 2,721
  • 23
  • 37