split string into substrings based on delimiter

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
thefeduke
Posts: 211
Joined: 05 Apr 2015 13:06
Location: MA South Shore, USA

Re: split string into substrings based on delimiter

#31 Post by thefeduke » 23 Dec 2017 13:33

I have modified my last post that contained code with comments to correct the negative return code and to point out a restriction in using overlapping search strings.
John A.

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: split string into substrings based on delimiter

#32 Post by Aacini » 19 Feb 2018 15:25

I developed a new method that allows to use this technique to split two variables in the same replacement line, although it uses a trick in order to avoid the REM command that is usually used for this purpose, but that can not work in this case. The trick can also be used to split more than two variables.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=1.0.2.25"
set "vars=Major Minor Revision Subrev"

set "p=%%"
set "v=%vars: =" & set "s=!str:*.=!" & call set "!v!=!p!str:.!s!=!p!" & set "str=!s!" & set "v=%" & set "!v!=!s!"

echo Major: %Major%, Minor: %Minor%, Revision: %Revision%, Subrev: %Subrev%
Antonio

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: split string into substrings based on delimiter

#33 Post by jeb » 19 Feb 2018 16:33

Hi Aacini,

really nice :!: :D
It takes a minute to understand your code :idea:

Once upon a time, someone told me, that it's nice to explain a bit more and ever after I tried hard. :D

I suppose for some readers it would be helpful, when you show your idea.

jeb

IcarusLives
Posts: 175
Joined: 17 Jan 2016 23:55

Re: split string into substrings based on delimiter

#34 Post by IcarusLives » 25 Feb 2018 20:50

Aacini wrote:
19 Feb 2018 15:25
I developed a new method that allows to use this technique to split two variables in the same replacement line, although it uses a trick in order to avoid the REM command that is usually used for this purpose, but that can not work in this case. The trick can also be used to split more than two variables.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=1.0.2.25"
set "vars=Major Minor Revision Subrev"

set "p=%%"
set "v=%vars: =" & set "s=!str:*.=!" & call set "!v!=!p!str:.!s!=!p!" & set "str=!s!" & set "v=%" & set "!v!=!s!"

echo Major: %Major%, Minor: %Minor%, Revision: %Revision%, Subrev: %Subrev%
Antonio
Aacini,

I'm really interested in how this works, but I'm struggling to understand it. Can you please explain with some detail this method?

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: split string into substrings based on delimiter

#35 Post by Aacini » 26 Feb 2018 09:21

jeb wrote:
19 Feb 2018 16:33
Hi Aacini,

really nice :!: :D
It takes a minute to understand your code :idea:

Once upon a time, someone told me, that it's nice to explain a bit more and ever after I tried hard. :D

I suppose for some readers it would be helpful, when you show your idea.

jeb
IcarusLives wrote: I'm really interested in how this works, but I'm struggling to understand it. Can you please explain with some detail this method?

The purpose of the method is to split two strings in their parts. This can be easily done in two lines and then combine the parts in a third line:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=1.0.2.25"
set "vars=Major Minor Revision Subrev"

set "i=1" & set "s!i!=%str:.=" & set /A i+=1 & set "s!i!=%"
set "i=1" & set "v!i!=%vars: =" & set /A i+=1 & set "v!i!=%"
for /L %%i in (1,1,%i%) do set "!v%%i!=!s%%i!"

echo Major: %Major%, Minor: %Minor%, Revision: %Revision%, Subrev: %Subrev%
In this way, the goal is to complete the same split in just one line. To do that, in each division of the first string we must "split" the second string, that is, perform the equivalent process: take the value before the first dot to assign it to the variable, and ignore the rest of values. A first attempt to ignore the rest of the values (after the first dot) is inserting a "REM" command in the usual way:

Code: Select all

set "p=%%"
set "v=%vars: =" & call set "!v!=!p!str:.=& rem !p!" & set "str=!str:*.=!" & set "v=%" & set "!v!=!s!"
                   ^^^^          \________________/
The purpose of the marked part is to insert a REM command in place of the dots in the value of STR variable. However, this method have two problems: it is necessary to escape several special characters in this part in order to correctly execute the REM command, otherwise it is just assigned to the !V! variable. Anyway, when the REM command is successfully executed, it causes to ignore all commands after it, including the rest of commands that should split the rest of parts in the first string.

A workaround to do the same process without using a REM command is simple: first, take the rest of values after the first dot: set "s=!str:*.=!"; then, eliminate such a part from the variable (this gives just the first part): call set "!v!=!p!str:.!s!=!p!". Finally, assign the rest of values to the same variable (in preparation for the next part): set "str=!s!".

Code: Select all

set "v=%vars: =" & set "s=!str:*.=!" & call set "!v!=!p!str:.!s!=!p!" & set "str=!s!" & set "v=%" & set "!v!=!s!"
Note that three previous steps are performed in each part of the split of first variable, that is, they are placed inside the only percent-signs in the line. At end, the last values remains in their respective variables but have not been processed, so an additional set "!v!=!s!" is inserted at end of line...

As jeb would say: it's obvious! 8)

Antonio

IcarusLives
Posts: 175
Joined: 17 Jan 2016 23:55

Re: split string into substrings based on delimiter

#36 Post by IcarusLives » 28 Feb 2018 11:49

OOOOHHH Okay now I can see it. Thank you so much for the great explanation!

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: split string into substrings based on delimiter

#37 Post by Aacini » 19 Aug 2018 10:25

I have extended the last method I posted here in order to easily split a string in several parts specified by the length of each one:

Code: Select all

@echo off
setlocal EnableDelayedExpansion


call :Split "10225" "Major:1 Minor:1 Revision:1 Subrev:2"
rem The result should be Major:1, Minor:0, Revision:2, Subrev:25
echo Major: %Major%, Minor: %Minor%, Revision: %Revision%, Subrev: %Subrev%


for /F "tokens=2 delims==" %%t in ('wmic os get localdatetime /value') do set "dateTime=%%t"
echo/
echo DateTime: %dateTime%
call :Split "%dateTime%" "Year:4 Month:2 Day:2 Hour:2 Minute:2 Second:2 _:7 Offset:4"
echo Year:%Year%  Month:%Month%  Day:%Day%  Hour:%Hour%  Minute:%Minute%  Second:%Second%  Offset:%Offset%

goto :EOF



:Split string "var1:len1 var2:len2 ..."
set "str=%~1" & set "vars=%~2 " & set "p=%%"
set "v=%vars: =" & set "len=!v:*:=!" & call set "name=!p!v::!len!=!p!" & call set "!name!=!p!str:~0,!len!!p!" & call set "str=!p!str:~!len!!p!" & set "v=%"
exit /B
Output:

Code: Select all

Major: 1, Minor: 0, Revision: 2, Subrev: 25

DateTime: 20180819111956.885000-300
Year:2018  Month:08  Day:19  Hour:11  Minute:19  Second:56  Offset:-300
The method is exactly the same than the last explained one, so no further explanations here... :roll:

Antonio

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: split string into substrings based on delimiter

#38 Post by aGerman » 19 Aug 2018 13:07

That's neat. Thanks for sharing, Antonio!

Steffen

IcarusLives
Posts: 175
Joined: 17 Jan 2016 23:55

Re: Efficient Array Management Operations in Batch files

#39 Post by IcarusLives » 23 Sep 2021 15:50

This magic line

Code: Select all

set "i=1" & set "s!i!=%str:.=" & set /A i+=1 & set "s!i!=%"
I did not expect this resulted behavior. Quiet astounding! I imagine this method is much faster compared to intuitive loops. :?:

I'm always so overwhelmed with excitement with releases like this.

As always, GREAT WORK!
Last edited by aGerman on 18 Oct 2021 12:56, edited 1 time in total.
Reason: This, and the following two posts have been moved from https://www.dostips.com/forum/viewtopic.php?f=3&t=10214

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: Efficient Array Management Operations in Batch files

#40 Post by Squashman » 23 Sep 2021 15:59

IcarusLives wrote:
23 Sep 2021 15:50
This magic line

Code: Select all

set "i=1" & set "s!i!=%str:.=" & set /A i+=1 & set "s!i!=%"
I did not expect this resulted behavior. Quiet astounding! I imagine this method is much faster compared to intuitive loops. :?:

I'm always so overwhelmed with excitement with releases like this.

As always, GREAT WORK!
Yep this was discussed about 6 years ago in this thread.
viewtopic.php?f=3&t=6429

IcarusLives
Posts: 175
Joined: 17 Jan 2016 23:55

Re: Efficient Array Management Operations in Batch files

#41 Post by IcarusLives » 23 Sep 2021 16:05

Squashman wrote:
23 Sep 2021 15:59
Yep this was discussed about 6 years ago in this thread.
viewtopic.php?f=3&t=6429
That's exactly why it's so amazing. Because even after coding in batch for so many years, I'm STILL learning things. I just think that's really great, and that's why I love this site.

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: split string into substrings based on delimiter

#42 Post by Squashman » 26 Nov 2021 14:25

Aacini wrote:
19 Feb 2018 15:25
I developed a new method that allows to use this technique to split two variables in the same replacement line, although it uses a trick in order to avoid the REM command that is usually used for this purpose, but that can not work in this case. The trick can also be used to split more than two variables.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=1.0.2.25"
set "vars=Major Minor Revision Subrev"

set "p=%%"
set "v=%vars: =" & set "s=!str:*.=!" & call set "!v!=!p!str:.!s!=!p!" & set "str=!s!" & set "v=%" & set "!v!=!s!"

echo Major: %Major%, Minor: %Minor%, Revision: %Revision%, Subrev: %Subrev%
Antonio
I used one of your concepts in this thread to answer a question on StackOverFlow. Then I was bored and figured why not make an array if there is more than one line of output.

Code: Select all

@echo off
setlocal enabledelayedexpansion

REM Get Driver Query Header Row to use has variables
for /f "delims=" %%G in ('driverquery /V /FO CSV') do (set "vars=%%~G" & GOTO NEXT)
:NEXT
REM Cleanup variable names
SET "vars=%vars: =_%"
SET "vars=%vars:(=_%"
SET "vars=%vars:)=%"
SET "vars=%vars:path=dPath%"
SET "vars=%vars:","= %"

REM 
SET "count=0"
set "p=%%"
for /f "delims=" %%G in ('driverquery /V /FO CSV ^|findstr /IC:"Virtual WiFi"') do (
	set /A "count+=1"
	set "str=%%~G"
	set "v=%vars: =" & set "s=!str:*","=!" & call set "!v!!count!=!p!str:","!s!=!p!" & set "str=!s!" & set "v=%" & set "!v!!count!=!s!"
)

REM Display Driver Query Array
FOR /L %%C IN (1,1,%count%) DO FOR %%G IN (%vars%) DO SET %%G%%C
Which will just output to two entries from the Driver Query.

Code: Select all

Module_Name1=vwififlt
Display_Name1=Virtual WiFi Filter Driver
Description1=Virtual WiFi Filter Driver
Driver_Type1=Kernel
Start_Mode1=System
State1=Running
Status1=OK
Accept_Stop1=TRUE
Accept_Pause1=FALSE
Paged_Pool_bytes1=4,096
Code_bytes1=53,248
BSS_bytes1=0
Environment variable Link_Date1 not defined
dPath1=C:\WINDOWS\system32\drivers\vwififlt.sys
Init_bytes1=4,096
Module_Name2=vwifimp
Display_Name2=Virtual WiFi Miniport Service
Description2=Virtual WiFi Miniport Service
Driver_Type2=Kernel
Start_Mode2=Manual
State2=Running
Status2=OK
Accept_Stop2=TRUE
Accept_Pause2=FALSE
Paged_Pool_bytes2=4,096
Code_bytes2=32,768
BSS_bytes2=0
Environment variable Link_Date2 not defined
dPath2=C:\WINDOWS\system32\drivers\vwifimp.sys
Init_bytes2=4,096

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: split string into substrings based on delimiter

#43 Post by Aacini » 22 Dec 2021 14:46

I discovered a new simpler (and clearer) method to assign values to several variables in the same line. I think this is the simplest way to do it:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=1.0.2.25"
set "Major=%str:.=" & set "Minor=!Revision!" & set "Revision=!Subrev!" & set "Subrev=%"
echo Major: %Major%, Minor: %Minor%, Revision: %Revision%, Subrev: %Subrev%
If the values are numeric, then the multiple assignments can be performed in an even simpler way via a SET /A command:

Code: Select all

set /A "Major=%str:.=" & set /A "Minor=Revision,Revision=Subrev,Subrev=%"
Antonio

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: split string into substrings based on delimiter

#44 Post by Squashman » 22 Dec 2021 16:54

Aacini wrote:
22 Dec 2021 14:46
I discovered a new simpler (and clearer) method to assign values to several variables in the same line. I think this is the simplest way to do it:
True but not as dynamic. If I wanted to add another sub version all I have to do is edit the two variables.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=1.0.2.25.69"
set "vars=Major Minor Revision Subrev Last"

set "p=%%"
set "v=%vars: =" & set "s=!str:*.=!" & call set "!v!=!p!str:.!s!=!p!" & set "str=!s!" & set "v=%" & set "!v!=!s!"

FOR %%G IN (%vars%) DO call set /p ".=%%G: %%%%G%%, "<nul

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: split string into substrings based on delimiter

#45 Post by Aacini » 28 Dec 2021 01:55

Squashman wrote:
22 Dec 2021 16:54
Aacini wrote:
22 Dec 2021 14:46
I discovered a new simpler (and clearer) method to assign values to several variables in the same line. I think this is the simplest way to do it:
True but not as dynamic. If I wanted to add another sub version all I have to do is edit the two variables.

Code: Select all

. . .
Although you are right, the last method is the simplest and purest way to write such a multiple assignment in Batch because it does not require any additional elements besides the variable names (unlike the previous method which has a lot of strange elements), making it easier for beginners to understand and use in Batch files. Anyway, if dynamic change is required, then the last method can also be used automatically through this modification:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=1.0.2.25.69"
set "vars=Major Minor Revision Subrev Last "

set "$2=" & set "$3=" & set "$4="
set "$1=%vars: =" & (if not defined $3 set "$3=!$1!") & set "$4=!$4!,!$2!=!$3!" & set "$2=!$3!" & set "$3=%"
set "$4=!$4:*%$1%,=!,%$2%"
set "%$2%=%str:.=" & set /A "!$4!=%"

for %%G IN (%vars%) do set /P "=%%G: !%%G!, " < NUL
Antonio

Post Reply