Search code examples
arraysstringbatch-filetextwindows-10

Batch script: extract text after/before last/first occurrence of characters and store it in array


Suppose I have the following content in my file under "%userprofile%\~.txt":

Monitor: Generic PnP Monitor
Device: \\.\DISPLAY1
Adapter: Intel(R) UHD Graphics 630
(1920 x 1080 x 32 bpp) 60Hz default up, attached (-1920,0)

Monitor: Generic PnP Monitor
Device: \\.\DISPLAY4
Adapter: NVIDIA Quadro P2000
(1280 x 1024 x 32 bpp) 60Hz default up, attached (1920,0)

Monitor: Generic PnP Monitor
Device: \\.\DISPLAY8
Adapter: DisplayLink USB Device
(1920 x 1080 x 32 bpp) 60Hz default up, attached, primary (0,0)

The number of text blocks can vary.

What I want to get is the first of the two coordinates appearing on the last line of each block, so according to the example, the result should be:

-1920
1920
0

To do so in a batch script, I first analyze the file by an initial for loop, that retrieves the lines containing the string "default up, attached".

Then for each retrieved string, I search for the text after the last occurrence of (.

From the previous results, I search for the text before the first occurrence of ,.

I found a solution that works outside the for loop (see lines marked with ** below), but I want these lines to be inside the loop. I tried lines marked with * below but the script exits and I have no clue what the error is. Hopefully a trivial missing piece. Please bear with my low batch scripting knowledge.

My script:

@echo off
setlocal EnableDelayedExpansion
set Cnt=0
FOR /F "tokens=*" %%a IN ('findstr "default up, attached" "%userprofile%\~.txt"') DO (
  set /a Cnt+=1
  set result=%%a
  for %%b in ("%result:(=" "%") do set "result=%%~b"                          <= * THESE LINES DON'T WORK!!!
  for /f "tokens=1 delims=," %%c in ("%result%") do set "result=%%~c"         <= * THESE LINES DON'T WORK!!!
  call Set Monitors[%%Cnt%%]=!result!
)
for %%b in ("%Monitors[1]:(=" "%") do set "Monitors[1]=%%~b"                  <= ** THESE LINES WORK
for %%b in ("%Monitors[2]:(=" "%") do set "Monitors[2]=%%~b"                  <= ** THESE LINES WORK
for %%b in ("%Monitors[3]:(=" "%") do set "Monitors[3]=%%~b"                  <= ** THESE LINES WORK
for /f "tokens=1 delims=," %%c in ("%Monitors[1]%") do set "Monitors[1]=%%~c" <= ** THESE LINES WORK
for /f "tokens=1 delims=," %%c in ("%Monitors[2]%") do set "Monitors[2]=%%~c" <= ** THESE LINES WORK
for /f "tokens=1 delims=," %%c in ("%Monitors[3]%") do set "Monitors[3]=%%~c" <= ** THESE LINES WORK
echo %Monitors[1]%
echo %Monitors[2]%
echo %Monitors[3]%
pause

Solution

  • An alternative is to make use of powershell regex to do this:

    @Echo off
    
    :# Replace with actual filename
     Set "File=%~dp0in.txt"
     Set "Content=\(-?\d+,\d+\)$"
     Set "Prefix=^.*?,+ \w+ \("
     Set "Suffix=,\d*\)"
    
    :# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_regular_expressions?view=powershell-7.1
    
    Set "[i]=1"
    For /f "Delims=" %%G in ('
     powershell -nologo -noprofile -c ^
     "(GC "%File%") -match '%Content%' | ForEach {"$_" -replace '%Prefix%' -replace '%Suffix%'}
    ')Do Call Set /A "[i]+=1","Monitor[%%[i]%%]=%%G"
    
     Set Monitor[
    
    Goto :Eof