4

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.

RonBurgundy
  • 45
  • 1
  • 3

3 Answers3

5

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%
Stephan
  • 53,940
  • 10
  • 58
  • 91
  • Perfect, i was toying with the tokens part too, would have never come to this answer though. Cheers for the quick answer! – RonBurgundy Jun 12 '17 at 15:40
  • I like this idea. I'm curious if someone is willing to post a general approach which is free of any possible false results. – 303 Jun 12 '17 at 15:41
  • @treintje: I'm sure, someone will find a way to make it fail, but it should be quite robust (at least for reasonable strings). See my edit. – Stephan Jun 12 '17 at 16:04
  • (found a way to make it fail myself `:D` : `set "string=1>7.0% 9.0&1.04.%0!3"` (the two stray `%` make the string(s) inside a (nondefined) variable)) – Stephan Jun 12 '17 at 16:06
  • My reasonable string `set "string=Tim says:"There is a cat and a dog""` fails with `The command "is" is wrong or unknown`. I know, it's not quite a build number, but I like bullet proof solutions – jeb Jun 12 '17 at 16:11
  • @Stephan I don't really consider `set "string=1>7.0% 9.0&1.04.%0!3"` to be a false result because it should be known to use double percent signs to indicate a single percent sign character. @jeb How about stripping the double quotes when comparing the string? `if not "%string:"=%" == "%oldstring:"=%" ...` The double quotes don't affect the count of periods so would that be acceptable? Or does it break something else which I've overlooked? – 303 Jun 12 '17 at 16:38
  • @treintje: then `Tim says:"There is a cat. And a dog"` gives `2`. It's your choice, whether you expect `1` or `2`. In terms of general string management, if something is enclosed in quotes it should be *one* thing, so it should be `1`. – Stephan Jun 12 '17 at 16:46
  • @jeb, though I like the idea of this approach, I believe there is no chance to create a reliable solution based on it; `for` consumes wild-cards like `*`, for example, which cannot be easily removed or replaced using the sub-string replacement syntax; however, there is a different way -- see [my answer](https://stackoverflow.com/a/44506901), which I think is bullet-proof... – aschipfl Jun 12 '17 at 19:09
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 (|).

aschipfl
  • 33,626
  • 12
  • 54
  • 99
1

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""