36

I'm trying to split a string in a batch file using a string (rather than a character) as the delimiter.

The string has the format:

string1 by string2.txt

The delimiter is by (yes, space, the word 'by', followed by space). The output I want is:

string1

string2

So, basically, split the string into 2 parts by the delimiter by and remove the suffix from the second string. How can I do this?

aschipfl
  • 33,626
  • 12
  • 54
  • 99
Bud
  • 709
  • 2
  • 11
  • 28

5 Answers5

56

Try this:

for /F "tokens=1,3 delims=. " %%a in ("%string%") do (
   echo %%a
   echo %%b
)

that is, take the first and third tokens delimited by space or point...

Aacini
  • 65,180
  • 12
  • 72
  • 108
  • nice and short - although the delimiter string can be any word, not only `by`. – Stephan May 12 '14 at 06:05
  • to check for `by` as delimiter: `for /f "tokens=1-3 delims=. " %%a in ("%string%") do ( if "%%b"="by" echo %%a, %%c )` – Stephan May 12 '14 at 06:12
  • 2
    It is simpler this way: `for /F "tokens=1,2 delims=." %%a in ("%string: by =.%") do echo %%a, %%b` – Aacini May 12 '14 at 11:35
  • 3
    No, thanks. I think the OP should realize that the answer to the question is to take 1st and 3rd tokens, that is, I don't think he wants that 2nd token be precisely `" by "` (just my opinion `:)` – Aacini May 12 '14 at 11:48
  • How do you split by a double quote? – AnnanFay Mar 14 '19 at 14:06
  • 1
    @Annan: `for /F "tokens=1,2 delims=." %%a in (^"%var:"=.%^") do echo %%a,%%b` – Aacini Mar 14 '19 at 16:13
  • Is this possible for more than 24 chars? How can i access %%z+1 with this? – Odihase Oct 09 '20 at 16:34
  • @Odihase: I am afraid I don't understand your question. Please, be more specfic or add a short example... – Aacini Oct 10 '20 at 20:41
  • @Aacini echo %%a, %%b, ... , %%z gives you 24 parameters in total, which can be accessed without a "switch" is needed, while doing the same for "for /F "tokens=1,2 delims=." %%1 in (^"%var:"=.%^") do echo %%1,%%2" will give you 10 accessible parameters before a switch is required. The question is, if there is a possibility beneath the known letters (%%a) or numbers (%%1) which can provide you with more than 24 paremeters before a switch is required – Odihase Oct 12 '20 at 10:14
  • @Odihase: Your question have no relation to this problem ("Split string with string as delimiter") nor to my answer. Your question have also a couple unclear details. For example: `%%a, %%b, ..., %%z` gives **26** FOR /F _tokens_ and I don't understand what you mean with _a "switch" is needed_. What kind of "switch"? However, you may read an answer to your question at [Using many "tokens=..." in FOR /F command in a simple way](https://www.dostips.com/forum/viewtopic.php?f=3&t=7703) – Aacini Oct 12 '20 at 21:36
18

I recently discovered an interesting trick that allows to "Split String With String As Delimiter", so I couldn't resist the temptation to post it here as a new answer. Note that "obviously the question wasn't accurate. Firstly, both string1 and string2 can contain spaces. Secondly, both string1 and string2 can contain ampersands ('&')". This method correctly works with the new specifications (posted as a comment below Stephan's answer).

@echo off
setlocal

set "str=string1&with spaces by string2&with spaces.txt"

set "string1=%str: by =" & set "string2=%"
set "string2=%string2:.txt=%"

echo "%string1%"
echo "%string2%"

For further details on the split method, see this post.

Aacini
  • 65,180
  • 12
  • 72
  • 108
  • 2
    Can you explain why this works? It's super confusing to me. – Andrew Oct 31 '18 at 03:03
  • 5
    @Andrew: Is simple... This line: `set "string1=%str: by =" & set "string2=%"` just replaces this part in str: " by " by this one: `" & set "string2=`, and _then_ the resulting line is executed. I suggest you to do the same thing using your text editor: first enter this line: `set "string1=string1&with spaces by string2&with spaces.txt"` and then perform the previous replacement; the resulting line should be this one: `set "string1=string1&with spaces" & set "string2=string2&with spaces.txt"`. You may also remove the `@echo off` line, run the program and review in the screen the executed lines. – Aacini Oct 31 '18 at 03:53
8
@ECHO OFF
SETLOCAL
SET "string=string1 by string2.txt"
SET "string=%string:* by =%"
ECHO +%string%+

GOTO :EOF

The above SET command will remove the unwanted data. Result shown between + to demonstrate absence of spaces.

Formula: set var=%somevar:*string1=string2%

will assign to var the value of somevar with all characters up to string1 replaced by string2. The enclosing quotes in a set command ensure that any stray trailing spaces on the line are not included in the value assigned.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • 2
    Is there a way to use that to get the part before the by ? I tried `SET "string2=%string: by *=%"` but that didn't work. – Dennis van Gils Dec 10 '15 at 11:29
  • @magoo, looks like your method is very neat, I used this to edit my registry, but somehow its not working when `%LOCALAPPDATA%\Microsoft\WindowsApps` is in `PATH` variable, I work around it by removing it, do what I need with this method, then reappend it – Jonny Soe Dec 12 '22 at 19:11
  • @JonnySoe: Can't say I'm following. You'd need to post a question specifying precisly what the before situation is, the desired outcome and the method you are using. – Magoo Dec 12 '22 at 19:25
  • @Magoo, my apologies necro, my mistake when editing the registry, I was matching against `REG_SZ` so it failed to split the string by the `REG_SZ` delimiter, I used `setx /m` to remove `WindowsApps` unnecessarily so this changes the registry type to `REG_SZ` instead of `REG_EXPAND_SZ` then splitting by this delimiter works fine now, thanks! – Jonny Soe Dec 13 '22 at 02:55
2

I expanded Magoos answer to get both desired strings:

@ECHO OFF
SETLOCAL enabledelayedexpansion
SET "string=string1 by string2.txt"
SET "s2=%string:* by =%"
set "s1=!string: by %s2%=!"
set "s2=%s2:.txt=%"
ECHO +%s1%+%s2%+

EDIT: just to prove, my solution also works with the additional requirements:

@ECHO OFF
SETLOCAL enabledelayedexpansion
SET "string=string&1 more words by string&2 with spaces.txt"
SET "s2=%string:* by =%"
set "s1=!string: by %s2%=!"
set "s2=%s2:.txt=%"
ECHO "+%s1%+%s2%+"
set s1
set s2

Output:

"+string&1 more words+string&2 with spaces+"
s1=string&1 more words
s2=string&2 with spaces
Stephan
  • 53,940
  • 10
  • 58
  • 91
  • Thank you - but obviously my question wasn't accurate. Firstly, both string1 and string2 can contain spaces. Secondly, both string1 and string2 can contain ampersands ('&'). Thanks for all the answers, hopefully someone can come up with an answer bearing in mind the two extra conditions. – Bud May 14 '14 at 19:20
0

I've found two older scripts that use an indefinite or even a specific string to split. As an approach, these are always helpful.

https://www.administrator.de/contentid/226533#comment-1059704 https://www.administrator.de/contentid/267522#comment-1000886

@echo off
:noOption
if "%~1" neq "" goto :nohelp
echo Gibt eine Ausgabe bis zur angebenen Zeichenfolge&echo(
echo %~n0 ist mit Eingabeumleitung zu nutzen
echo %~n0 "Zeichenfolge" ^<Quelldatei [^>Zieldatei]&echo(
echo    Zeichenfolge    die zu suchende Zeichenfolge wird mit FIND bestimmt
echo            ohne AusgabeUmleitung Ausgabe im CMD Fenster
exit /b
:nohelp
setlocal disabledelayedexpansion
set "intemp=%temp%%time::=%"
set "string=%~1"
set "stringlength=0"
:Laenge string bestimmen
for /f eol^=^

^ delims^= %%i in (' cmd /u /von /c "echo(!string!"^|find /v "" ') do set /a Stringlength += 1

:Eingabe temporär speichern
>"%intemp%" find /n /v ""

:suchen der Zeichenfolge und Zeile bestimmen und speichen
set "NRout="
for /f "tokens=*delims=" %%a in (' find "%string%"^<"%intemp%" ') do if not defined NRout (set "LineStr=%%a"
  for /f "delims=[]" %%b in ("%%a") do set "NRout=%%b"
)
if not defined NRout >&2 echo Zeichenfolge nicht gefunden.& set /a xcode=1 &goto :end
if %NRout% gtr 1 call :Line
call :LineStr

:end
del "%intemp%"
exit /b %xcode%

:LineStr Suche nur jeden ersten Buchstaben des Strings in der Treffer-Zeile dann Ausgabe bis dahin
for /f eol^=^

^ delims^= %%a in ('cmd /u /von /c "echo(!String!"^|findstr .') do (
  for /f "delims=[]" %%i in (' cmd /u /von /c "echo(!LineStr!"^|find /n "%%a" ') do (
    setlocal enabledelayedexpansion
    for /f %%n in ('set /a %%i-1') do if !LineStr:^~%%n^,%stringlength%! equ !string! (
      set "Lineout=!LineStr:~0,%%n!!string!"
      echo(!Lineout:*]=!
      exit /b
    )
) )
exit /b 

:Line vorige Zeilen ausgeben
for /f "usebackq tokens=* delims=" %%i in ("%intemp%") do (
  for /f "tokens=1*delims=[]" %%n in ("%%i") do if %%n EQU %NRout%  exit /b
  set "Line=%%i"
  setlocal enabledelayedexpansion 
  echo(!Line:*]=!
  endlocal
)
exit /b

@echo off
:: CUTwithWildcards.cmd
:noOption
if "%~1" neq "" goto :nohelp
echo Gibt eine Ausgabe ohne die angebene Zeichenfolge.
echo Der Rest wird abgeschnitten.&echo(
echo %~n0 "Zeichenfolge" B n E [/i] &echo(
echo    Zeichenfolge    String zum Durchsuchen
echo    B   Zeichen Wonach am Anfang gesucht wird
echo    n   Auszulassende Zeichenanzahl
echo    E   Zeichen was das Ende der Zeichen Bestimmt
echo    /i  Case intensive
exit /b
:nohelp
setlocal disabledelayedexpansion
set  "Original=%~1"
set     "Begin=%~2"
set /a    Excl=%~3 ||echo Syntaxfehler.>&2 &&exit /b 1
set       "End=%~4"
if not defined end echo Syntaxfehler.>&2 &exit /b 1
set   "CaseInt=%~5"
:: end Setting Input Param
set       "out="
set      "more="
call :read Original
if errorlevel 1 echo Zeichenfolge nicht gefunden.>&2
exit /b
:read VarName B # E [/i]
for /f "delims=[]" %%a in (' cmd /u /von /c "echo  !%~1!"^|find /n %CaseInt% "%Begin%" ') do (
  if defined out exit /b 0
  for /f "delims=[]" %%b in (' cmd /u /von /c "echo !%1!"^|more +%Excl%^|find /n %CaseInt% "%End%"^|find "[%%a]" ') do (
    set "out=1"
    setlocal enabledelayedexpansion
    set "In=  !Original!"
    set "In=!In:~,%%a!"
    echo !In:^~2!
    endlocal
) )
if not defined out exit /b 1 
exit /b

::oneliner for CMDLine
set "Dq=""
for %i in ("*S??E*") do @set "out=1" &for /f "delims=[]" %a in ('cmd/u/c "echo  %i"^|find /n "S"') do @if defined out for /f "delims=[]" %b in ('cmd/u/c "echo %i"^|more +2^|find /n "E"^|find "[%a]"') do @if %a equ %b set "out=" & set in= "%i" &cmd /v/c echo ren "%i" !in:^~0^,%a!!Dq!)
pieh-ejdsch
  • 206
  • 1
  • 6