简体   繁体   中英

batch iterate string with whitespace delimiter, find word containing substring

I don't understand why this doesn't work

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set contents=sdflkm efsdf sdfkns CRQ239478239
for /f "tokens=1* delims= " %%i in ("%contents%") do (
  set str=%%i
  echo str: !str:~0,3!
    if "!str:~0,3!"=="CRQ" (
      set revision=!str!
    )
)
echo revision: %revision%

I want to extract the word in the string that begins with "CRQ". But this for loop only does one iteration, grabbing the first 3 letters of the string. The output is just str: sdf . It should check the first 3 letters of every word in the string, and if the first 3 letters are 'CRQ', it should set the revision variable to the word containing CRQ. How do I do this?

The for command will iterate through lines of input. Since your string only consists of a single line you only get 1 iteration through your loop.

The for loop is tokenizing that single line into multiple tokens. It is passing the first token to %i , then, thanks to the asterisk in tokens=1* , it puts the rest in %j . If you change your script a little, you can see this:

set contents=sdflkm efsdf sdfkns CRQ239478239
for /f "tokens=1*" %%i in ("%contents%") do (
  set str=%%i
  echo str: !str:~0,3!
  echo rest: %%j
    if "!str:~0,3!"=="CRQ" (
      set revision=!str!
    )
)
echo revision: %revision%

which outputs:

str: sdf
rest: efsdf sdfkns CRQ239478239
revisionx:

My solution is to create a subroutine that you can call recursively on the remaining tokens until you hit the one you want:

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set contents=sdflkm efsdf sdfkns CRQ239478239
call :ParseTokens %contents%
echo revision: %revision%

rem Subroutine ParseTokens
:ParseTokens
set ToParse=%*
for /f "tokens=1*" %%i in ("%ToParse%") do (
    set str=%%i
    if "!str:~0,3!"=="CRQ" (
      set revision=!str!
      exit /b
    ) else (
        call :ParseTokens %%j
    )
)
exit /b

Just change your For /F loop to a standard For loop:

@Echo Off
SetLocal EnableDelayedExpansion
Set "Contents=sdflkm efsdf sdfkns CRQ239478239"
Set "Revision="
For %%A In (%Contents%) Do (Set "Str=%%A"
    Echo Str: !Str:~,3!
    If /I "!Str:~,3!"=="CRQ" Set "Revision=!Str!")
Set "Str="
If Defined Revision Echo %Revision%
Pause

Change your for to a simple one and use %contents% without quotes.

for %%i in (%contents%) do (

Just another variant with a call and shifting arguments:

@echo off & SETLOCAL
set contents=sdflkm efsdf sdfkns CRQ239478239
Call :Sub %contents%
echo revision: %revision%
goto :eof
:sub
set str=%1
echo str: %str:~0,3%
if "%str:~0,3%"=="CRQ" set revision=%str%
If "%~2" neq "" (shift & goto :sub)

Just adding another method to achieve this, using a file as input called My CRQs.txt The idea here is to break up each string into words so findstr will only return what you asked off it.:

@echo off
for /f "usebackq delims=" %%i in ("My CRQs.txt") do (
   for %%a in (%%i) do echo %%a | findstr /IBRC:"CRQ"
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM