Пакетный скрипт: извлекает текст после/до последнего/первого вхождения символов и сохраняет его в массиве

#arrays #string #batch-file #text #windows-10

Вопрос:

Предположим, в моем файле в разделе «%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)

 

Количество текстовых блоков может варьироваться.

То, что я хочу получить, — это первая из двух координат, появляющихся в последней строке каждого блока, поэтому, согласно примеру, результат должен быть:

 -1920
1920
0
 

Чтобы сделать это в пакетном сценарии, я сначала анализирую файл с помощью начального цикла for, который извлекает строки, содержащие строку «по умолчанию вверх, прикреплено».

Затем для каждой полученной строки я ищу текст после последнего вхождения ( .

Из предыдущих результатов я ищу текст до первого появления , .

Я нашел решение, которое работает вне цикла for (см. Строки, отмеченные ** ниже), но я хочу, чтобы эти строки находились внутри цикла. Я попробовал строки, отмеченные * ниже, но скрипт завершается, и я понятия не имею, в чем ошибка. Надеюсь, тривиальный недостающий фрагмент. Пожалуйста, примите во внимание мои низкие знания в области пакетных сценариев.

Мой сценарий:

 @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
 

Комментарии:

1. У вас проблема с расширением переменной с первыми двумя отмеченными строками. Любая переменная, созданная или измененная внутри блока кода, заключенного в скобки, должна использовать отложенное расширение. Это означает, что вы используете восклицательные знаки с переменной вместо символов процента.

2. Независимо от этого я бы просто использовал левую и правую круглые скобки в качестве разделителей и использовал соответствующий токен, который был бы равен 3. Затем введите его через другую команду FOR /F и используйте запятую в качестве разделителя.

3. @Squashman не могли бы вы помочь мне в том, как будут выглядеть эти строки?

Ответ №1:

Альтернативой является использование регулярного выражения powershell для этого:

 @Echo off

:# Replace with actual filename
 Set "File=%~dp0in.txt"
 Set "Content=(-?d ,d )$"
 Set "Prefix=^.*?,  w  ("
 Set "Suffix=,d*)"

:# https://docs.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
 

Ответ №2:

Вы можете использовать круглые скобки и запятую в качестве разделителя, чтобы получить требуемое значение. Поскольку у вас есть дополнительные запятые в одной из строк ввода, для этого потребуются две вложенные FOR команды. Первый FOR разделит его на скобки и даст вам все, что находится между вторым набором скобок. Затем поместите этот вывод в другую FOR команду, чтобы разделить значение на запятую.

 @echo off
REM use the parentheses as a delimiter
FOR /F "tokens=3 delims=()" %%G IN ('findstr "default up, attached" "file.txt"') DO (
    REM USE the comma as a delimiter for the final split up of the variable.
    FOR /F "TOKENS=1 delims=," %%H IN ("%%~G") DO ECHO %%~H
)
 

Комментарии:

1. Спасибо, очень мило. Мне немного больше нравится решение регулярных выражений от @T3RR0R, так как я предполагаю, что содержание строк может измениться в будущем.