2

how can i split the string

"   This  is  a text  with  spaces    "

that is in the variable "string" into text parts without loosing the spaces ?

set string="#   This  is  a text  with  spaces    #"

should be split into

"#   This"
"  is"
"  a"
" text"
"  with"
"  spaces    #"

Using For /F "delims= " ... doesn't work because it eliminates all spaces.

Is there a 'simple' solution or can anyone explain how to parse the string character by character so i can count up spaces to first character, then read all characters until next space and write the counted spaces and the read characters together to a new/temp variable ??

thanks

4
  • 1
    What have the #s got to do with the matter? they seem to appear from thin air. Commented Apr 17, 2013 at 15:15
  • The # is to show the beginning and end of the string. But that doesn't matter because a string can also contain this # at the beginning and/or end. Commented Apr 18, 2013 at 2:39
  • Actually, it's very important - and still doesn't explain your output. I'll conclude you want to start a new substring at each space-sequence; but that would make your first substring # and second ` This;your second-last spaces` and your last ` #` - which is different from your posted result. Commented Apr 18, 2013 at 3:43
  • First two & last two strings must be treated separately. This makes the question more complicated. Commented Apr 18, 2013 at 4:46

5 Answers 5

3

Yeah, I don't really understand the # either. What is it about "    spaces    #" that makes it hold onto the trailing spaces, while all other elements keep the preceding but not the proceeding spaces?

Oh, well, effort spent in asking = effort spent in answering. Do with this what you will.

@if (@a==@b) @end /*

:: batch portion

@echo off
setlocal

call :split "#   This  is  a text  with  spaces    #"
exit /b

:split <string>
cscript /nologo /e:jscript "%~f0" "%~1"
goto :EOF

:: JScript portion */
WSH.Echo(WSH.Arguments(0).match(/\s*\S+/g).join('\n'));

Output:

#
   This
  is
  a
 text
  with
  spaces
    #

Update

If you want the first + second, and the penultimate + ultimate elements joined, modify the JScript portion of the above script as follows:

:: JScript portion */
var m = WSH.Arguments(0).match(/\s*\S+/g);
m[0] = m.shift() + m[0];
m[m.length - 2] += m.pop();
WSH.Echo(m.join('\n'));

Output:

#   This
  is
  a
 text
  with
  spaces    #

And if you want each element enclosed in quotation marks, change the last line as follows:

    WSH.Echo('"' + m.join('"\n"') + '"');

Output:

"#   This"
"  is"
"  a"
" text"
"  with"
"  spaces    #"
Sign up to request clarification or add additional context in comments.

2 Comments

The " spaces #" has trailing spaces because either the first word or the last word will have spaces on both sides.
So you want it split the way I have it, but the first + second and the penultimate + last elements joined. OK. I'll update my answer.
2

I don't see a simple solution in batch, though of course if you can consider powershell or javascript you'll be working with a more appropriate toolset for string manipulation.

Sticking with the batch requirement, you can loop through character by character and "collect" your words with something like this:

@echo off
setlocal enabledelayedexpansion

set "string=   This  is  a text  with  spaces    "

set idx=0
set "word="
set "char="
set "lastchar= "
:loop
if "!string:~%idx%!" equ "" goto :eof
set char=!string:~%idx%,1!
if "%char%" equ " " (
    if "%lastchar%" neq " " (
        echo [%word%]
        set word=%char%
    ) else (
        set word=%word%%char%
    )
) else (
    set word=%word%%char%
)
set lastchar=%char%
set /a idx=%idx%+1
goto loop

This script uses batch's substring feature !string:~%idx%,1 to grab a single character from the string, incrementing idx with each loop. Then it's just a matter of processing the word (echo in this example) when the previous character was not a space and the current one is.

This writes out:

[   This]
[  is]
[  a]
[ text]
[  with]
[  spaces]

Note that I'm ignoring the # you had in your example because I don't understand where they fit in.

Comments

2

the trick is substituting the contiguous spaces by just one space and the rest by some arbitrary character. Assuming your string does not contain #s and that there are no more than 9 contiguous spaces, you can try this

set st=%st:         = ########%
set st=%st:        = #######%
set st=%st:       = ######%
set st=%st:      = #####%
set st=%st:     = ####%
set st=%st:    = ###%
set st=%st:   = ##%
set st=%st:  = #%

then you may parse with for /f and substitute back your #s by spaces

setlocal enabledelayedexpansion
for /f %%a in ("%st%") do (
  set ss= %%a
  echo !ss:#= !
)  

note that set inside the parentheses block requires you to enable delayed expansion and to use the ! syntax (see HELP SET)

But this technique will only extract the first substring. To generalize, you need another trick, that is substituting the spaces into newlines so that the for /f will loop kinda line by line

note that in order to obtain a newline char you need to preserve the two blank lines after the set command

set nl=^


rem continue two lines down....
for /f %%a in ("%st: =!nl!%") do (
  set ss= %%a
  set ss=!ss:#= !
  echo [!ss!]
)  

1 Comment

+1, Nice answer as long as the number of consecutive spaces is reasonably constrained. I've written a more general search and replace based solution that relies on a minimal number of GOTOs. See my answer
2

Try this:

@echo off &setlocal enabledelayedexpansion
set "string=#   This  is  a text  with  spaces    #"

set string1=%string%
for %%i in (%string%) do (
    set string1=!string1: %%i = "%%i" !
    set /a strings+=1
)
set string1=#"%string1:~1,-1%"#
set string1=%string1:"= "%
for %%i in (%string1%) do (
    set /a count+=1
    set string2=%%i
    set string2=!string2: "=!
    set string2=!string2:"=!
    if !count! equ 2 (
     set $s1=!$s1!!string2!
    )else if !count! equ %strings% (
        set /a count-=1
        call set $s!count!=%%$s!count!%%!string2!
        ) else set $s!count!=!string2!
)
for /f "tokens=1*delims==" %%i in ('set "$s"') do echo "%%j"    

Output:

"#   This"
"  is"
"  a"
" text"
"  with"
"  spaces    #"

Comments

2

If I had to accomplish this obscure task, I would use a hybrid JScript/batch technique like in rojo's answer. However, I would use a REPL.BAT utility that I have already written. Assuming my REPL.BAT is in either the current folder, or else somewhere in the PATH, then the following will work:

@echo off
setlocal enableDelayedExpansion
set "string=#   This  is  a text  with  spaces    #"

:: Build an "array" of text parts
set cnt=0
for /f delims^=^ eol^= %%A in ('repl "([^ ])(?= )" "$1\n" xs string') do (
  set /a cnt+=1
  set "string!cnt!=%%A"
)

:: Print the array values
for /l %%N in (1 1 %cnt%) do echo string%%N=[!string%%N!]

But if I wanted a pure batch solution, I would use the fairly efficient method below:

@echo off
setlocal enableDelayedExpansion
set "string=#   This  is  a text  with  spaces    #"

:: Define LF to contain a single line feed character (0x0A)
set LF=^


:: Above 2 blank lines are critical - DO NOT REMOVE


:: Insert a line feed before every space
for %%n in ("!LF!") do set "string=!string: =%%~n !"

:loop  Remove line feeds sandwiched by spaces
for %%n in ("!LF!") do set "string2=!string: %%~n =  !"
if "!string2!" neq "!string!" (
  set "string=!string2!"
  goto :loop
)

:: Build an "array" of text parts: FOR /F splits the string at line feeds
set /a cnt=0
for /f delims^=^ eol^= %%A in ("!string!") do (
  set /a cnt+=1
  set "string!cnt!=%%A"
)

:: Print out the array values
for /l %%N in (1 1 %cnt%) do echo string%%N=[!string%%N!]

Both solutions above give the following output:

string1=[#]
string2=[   This]
string3=[  is]
string4=[  a]
string5=[ text]
string6=[  with]
string7=[  spaces]
string8=[    #]

Note that the FOR loop %%A expansion will corrupt the results if the string contains ! due to delayed expansion. This limitation can be eliminated with additional coding. All the other posted solutions that use a FOR loop suffer from this same limitation. (at least they did when I wrote this)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.