批处理文件决定4> 39,我该如何解决?

时间:2015-07-28 15:12:00

标签: batch-file

注意:文件Default.txt包含一行包含以下三个字符: 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

然而,当运行脚本时,它不会添加38个空格,而只会添加3个空格。 通过重新打开回声,我找到了它离开:空间循环的确切位置。

    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
    )

到目前为止,一切正常。 突然:

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

由于某种原因,4突然大于39,它继续前进到下一部分而不是增加变量并再次循环。

    C:\>set /a n-=1

    C:\>set /a ln+=1

    C:\>goto process

程序继续运行,只有3个空格被添加到变量中。 我不知道问题是什么,并且对任何见解都会感激不尽。

3 个答案:

答案 0 :(得分:1)

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

删除引文并尝试使用,引号通常与字符串一起使用。

答案 1 :(得分: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.

答案 2 :(得分: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).