Batch File Count all occurrences of a character wi

2020-04-11 07:02发布

问题:

I have a version number 17.06.01.01 and I would like to know how many entries there are split by a period.

My last piece of code was;

setlocal ENABLEDELAYEDEXPANSION
for /F "tokens=1-10 delims=." %%a in ("17.09.01.04.03") do (
set /a "iCount+=1"

echo %%a, !iCount!
)
endlocal

I've tried a host of 'For' commands but seem to be getting further away each time.

回答1:

replace every dot with a space (as a delimiter). Then count number of tokens:

@echo off
set "string=17.09.01.04.03"
set count=0
for %%a in (%string:.= %) do set /a count+=1
echo %count%

(May give false results, if there are other spaces, commas or tabs in the string, but should work nice for your example of version strings containing only numbers and dots)

@treintje:

echo off
set "string=1>7.0 9.0&1.04.0!3"
set count=0
:again
set "oldstring=%string%"
set "string=%string:*.=%"
set /a count+=1
if not "%string%" == "%oldstring%" goto :again
echo %count%


回答2:

For the sample string you provided, Stephan's approach is perfectly sufficient.

However, if the string contains token separators (white-spaces, ,, ;, =), quotation marks ("), wild-cards (*, ?) or other special characters (^, &, (, ), >, <, |) it might probably fail. You could of course replace most of such characters by others in advance, and use delayed expansion rather than immediate one, but this still does not resolve all issues (for instance, you cannot replace all = or * characters due to the sub-string replacement syntax).

The following approach however can deal with every arbitrary combination of all such characters. Basically it replaces every period (.) with a new-line (line-feed) character and lets find /C /V "" count the total number of lines.

@echo off
set "string=17.09.01.04.03"
setlocal EnableDelayedExpansion
if defined string (set ^"strtmp=!string:.=^
%= empty string =%
!^") else set "strtmp="
for /F %%C in ('cmd /V /C echo(^^!strtmp^^!^| find /C /V ""') do set /A "count=%%C-1"
echo "!string!" contains %count% periods.
endlocal

The periods become replaced by line-feeds in advance, using delayed expansion in order not to fail if any special characters occur. The for /F loop executes the command line cmd /V /C echo(^^!string^^!| find /C /V "" and captures its output in a variable, reduced by one as find /C /V "" actually returns the number of lines, which are separated by one less line-feeds (hence periods), originally. The double-escaped exclamation marks ^^! are needed in order to ensure that the variable strtmp is actually expanded within the explicitly invoked inner-most cmd instance, because otherwise, the contained multi-line string is not correctly transported into the pipe (|).



回答3:

A different approach comparing strLen before and after replacing the dots with nothing.

@Echo off&SetLocal EnableExtensions EnableDelayedExpansion
set "string=17.09.01.04.03"
set "str2=%string:.=%"
call :strlen string ret
call :strlen str2 ret2
Set /A "Dots=ret-ret2"
echo Number of dots in %string% is %Dots%
goto :Eof

:strLen string len
:$source http://www.dostips.com/?t=Function.strLen
(SETLOCAL ENABLEDELAYEDEXPANSION
 set "str=A!%~1!"
 set "len=0"
 for /L %%A in (12,-1,0) do (set /a "len|=1<<%%A"
    for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A")
)
ENDLOCAL&IF "%~2" NEQ "" SET /a %~2=%len%
EXIT /b

Test with strings from comments:

Pass: set "string=Tim says:"There is a cat and a dog""
Fail: set "string=1>7.0% 9.0&1.04.%0!3"
Pass: set "string=Tim says:"There is a cat. And a dog""