Regex в пакетных окнах - PullRequest
0 голосов
/ 15 ноября 2018

В настоящее время я работаю над пакетным заданием (и я тоже новичок в этом), чтобы получить список зависимостей maven. Работал, чтобы получить эти зависимости с помощью регулярных выражений, но безрезультатно. Я проверил свое регулярное выражение на этом сайте и похоже, что оно работает.

Проверены необходимые escape-символы внутри цикла FOR из этого вопроса stackoverflow , но, опять же, безрезультатно, поэтому я прибег к помощи здесь.

См. Ниже мой фрагмент кода esp. часть регулярного выражения, внешний цикл в порядке.

for /f "tokens=*" %%i in ('findstr "+- \\-"  dependency-list.txt') do (
    for /f "tokens=*" %%j in ('findstr /i /r "^^(.+^)\[:\]^(.+^)^(:jar:^)^(.+^)^(:compile^)" %%i') do (
        echo %%j
    )
)

А это пример данных, извлеченных из моего внешнего цикла:

[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile
[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile
[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile

Я хотел получить эти части только с помощью регулярных выражений:

commons-configuration:commons-configuration:jar:1.5:compile
org.owasp.esapi:esapi:jar:2.0.1:compile
commons-lang:commons-lang:jar:2.3:compile

Это ошибки, которые я получаю при попытке выполнить мой пакетный скрипт.

FINDSTR: Cannot open org.owasp.esapi:esapi:jar:2.0.1:compile
'+-' is not recognized as an internal or external command,
operable program or batch file.
| was unexpected at this time.

Любая помощь будет принята с благодарностью.

Примечание: Как только я смогу успешно выполнить свое регулярное выражение, внешний цикл можно удалить.

1 Ответ

0 голосов
/ 15 ноября 2018

Возможности FINDSTR для регулярных выражений очень ограничены, поскольку их можно прочитать при открытии окна командной строки и запуске findstr /? для получения справки. Возможности регулярных выражений FINDSTR далеки от регулярных выражений, совместимых с Perl или Boost.Regex или других реализаций регулярных выражений в синтаксисе Perl.

Нет опции, которую можно использовать для получения вывода FINDSTR только строкой, соответствующей регулярному выражению. Есть несколько опций, которые управляют выводом FINDSTR , но ни один для получения вывода только найденная строка.

Таким образом, необходимо удалить все оставшиеся данные, представляющие интерес, в строках, содержащих +- или \- в файле dependency-list.txt, другим способом. Командный процессор Windows предлагает только две команды для задач переформатирования строки: FOR и SET .

Пакетный файл ниже демонстрирует оба из них, принимая во внимание, что задержанное расширение необходимо при доступе к значению переменной среды, определенной / измененной в том же блоке команд.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
cls
set "DeleteExample="
if exist dependency-list.txt goto GetData
(
    set "DeleteExample=1"
    echo First line with no data of interest.
    echo [INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile
    echo [INFO] ^|  +- commons-configuration:commons-configuration:jar:1.5:compile
    echo [INFO] ^|  ^|  +- commons-lang:commons-lang:jar:2.3:compile
    echo ;[INFO]^|  \- commons-lang:commons-lang:jar:4.5:compile
    echo Line trailing space at end +- 
    echo Line with no space at end  +-
    echo Line with just a hyphen character - somewhere on line.
    echo [INFO] ^|  ^|  +- !commons-configuration!:commons-configuration!:jar:5.2:compile
    echo Last line with no data of interest.
)>dependency-list.txt

:GetData
echo First solution
echo ==============
echo/
setlocal EnableDelayedExpansion
for /F "tokens=*" %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt 2^>nul') do (
    echo Line read: "%%I"
    set "Line=%%I"
    set "Line=!Line:*- =!"
    if defined Line echo Line work: "!Line!"
    rem More commands working with environment variable Line referenced with
    rem exclamation marks for delayed expansion on execution of the command line.
)
endlocal

echo/
echo Second solution
echo ===============
echo/
for /F "tokens=1* delims=-" %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt') do (
    if not "%%J" == "" (
        echo Line read: "%%J"
        set "Line=%%J"
        setlocal EnableDelayedExpansion
        call set "Line=%%Line:~1%%"
        if defined Line call echo Line work: "%%Line%%"
        rem More commands working with environment variable Line referenced
        rem with two percent signs on both side and with using command CALL.
        endlocal
    )
)

echo/
echo Third solution
echo ==============
echo/
for /F "tokens=1* delims=-" %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt 2^>nul') do (
    if not "%%J" == "" (
        echo Line read: "%%J"
        for /F "tokens=*" %%L in ("%%J") do if not "%%L" == "" (
            echo Line work: "%%L"
            rem More commands working with loop variable L.
        )
    )
)

echo/
echo Fourth solution
echo ===============
echo/
for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /R "+- \\-" dependency-list.txt 2^>nul') do (
    echo Line read: "%%I"
    set "Line=%%I"
    setlocal EnableDelayedExpansion
    set "Line=!Line:*- =!"
    if defined Line echo Line work: "!Line!"
    rem More commands working with environment variable Line referenced with
    rem exclamation marks for delayed expansion on execution of the command line.
    endlocal
)

echo/
echo Fifth solution
echo ==============
echo/
for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /L /C:+- /C:"\\-" dependency-list.txt') do (
    echo Line read: "%%I"
    set "Line=%%I"
    call :ProcessLine
)
goto EndDemo

:ProcessLine
set "Line=%Line:*- =%"
if defined Line echo Line work: "%Line%"
rem More commands working with environment variable Line referenced with
rem percent signs for expansion before execution of the command line.
goto :EOF

:EndDemo
if defined DeleteExample del dependency-list.txt
echo/
endlocal
pause

Вывод этого пакетного файла:

First solution
==============

Line read: "[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: "[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: "[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: "Line trailing space at end +- "
Line read: "Line with no space at end  +-"
Line work: "Line with no space at end  +-"
Line read: "[INFO] |  |  +- :commons-configuration:jar:5.2:compile"
Line work: ":commons-configuration:jar:5.2:compile"

Second solution
===============

Line read: " org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: " commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: " commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: " "
Line read: " !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

Third solution
==============

Line read: " org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: " commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: " commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: " "
Line read: " !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

Fourth solution
===============

Line read: "[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: "[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: "[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: ";[INFO]|  \- commons-lang:commons-lang:jar:4.5:compile"
Line work: "commons-lang:commons-lang:jar:4.5:compile"
Line read: "Line trailing space at end +- "
Line read: "Line with no space at end  +-"
Line work: "Line with no space at end  +-"
Line read: "[INFO] |  |  +- !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

Fifth solution
==============

Line read: "[INFO] +- org.owasp.esapi:esapi:jar:2.0.1:compile"
Line work: "org.owasp.esapi:esapi:jar:2.0.1:compile"
Line read: "[INFO] |  +- commons-configuration:commons-configuration:jar:1.5:compile"
Line work: "commons-configuration:commons-configuration:jar:1.5:compile"
Line read: "[INFO] |  |  +- commons-lang:commons-lang:jar:2.3:compile"
Line work: "commons-lang:commons-lang:jar:2.3:compile"
Line read: ";[INFO]|  \- commons-lang:commons-lang:jar:4.5:compile"
Line work: "commons-lang:commons-lang:jar:4.5:compile"
Line read: "Line trailing space at end +- "
Line read: "Line with no space at end  +-"
Line work: "Line with no space at end  +-"
Line read: "[INFO] |  |  +- !commons-configuration!:commons-configuration!:jar:5.2:compile"
Line work: "!commons-configuration!:commons-configuration!:jar:5.2:compile"

Первые четыре решения выполняются в отдельном командном процессе, запущенном с cmd.exe /C в фоновом режиме командной строки:

C:\Windows\System32\findstr.exe /R "+- \\-" dependency-list.txt

Эта командная строка приводит к поиску в файле dependency-list.txt в текущем каталоге, который может отличаться от каталога в пакетном файле с регулярным выражением с учетом регистра для строк, содержащих +- или \-.

Пятое решение запускается в отдельном командном процессе командной строки:

C:\Windows\System32\findstr.exe /L /C:+- /C:"\\-" dependency-list.txt

Эта командная строка находит те же строки, но с использованием буквенного поиска с учетом регистра для поиска строк, содержащих либо +-, либо \-.

FINDSTR ничего не выводит в STDOUT , а также ничего в STDERR , если не найдено ни одной строки, содержащей +- или \-.

FOR записывает вывод в STDOUT отдельного командного процесса и обрабатывает вывод построчно.

Пустые строки игнорируются FOR , так как по умолчанию также строки, начинающиеся с точки с запятой, потому что eol=; является значением по умолчанию для символа конца строки. FOR по умолчанию разбивает строку на подстроки (токены), используя обычный пробел и символ горизонтальной табуляции в качестве разделителей строк, и назначает только первую строку с пробелом / символ табуляции для указанной переменной цикла.

Первое решение

Первое решение изменяет поведение обработки строки на FOR , используя опцию tokens=*, что приводит к удалению всех начальных пробелов / табуляций из строки, и если что-то осталось, назначается оставшаяся часть строки, включая пробелы / табуляции в указанной переменной цикла I. Строки в выводе, начинающиеся с Line read:, показывают строку, назначенную переменной цикла I после обработки строки с помощью FOR .

Эта строка присваивается переменной окружения Line. Затем все до первого появления строки, состоящей из дефиса и пробела, удаляется из строки с помощью подстановки строки, выполняемой командой SET с использованием отложенного расширения переменных среды, как требуется при обращении к значению переменной среды определяется / изменяется внутри командного блока, начиная с ( и заканчивая соответствием ).

Если после подстановки строки еще что-то осталось, в результате чего переменная окружения Line все еще определяется, эта оставшаяся часть строки выводится с Line work:, чтобы увидеть, что было сделано подстановкой строки.

Это решение быстрое, но имеет недостатки, заключающиеся в том, что строки, начинающиеся с точки с запятой, игнорируются FOR , а постоянное включение отложенного расширения переменной среды приводит к тому, что строка, содержащая один или несколько восклицательных знаков, обрабатывается неправильно. Однако это лучшее решение для файла dependency-list.txt, не содержащего интересующих строк, начинающегося с ; и содержащего один или несколько !.

Второй раствор

Второе решение использует команду FOR , чтобы разбить каждую непустую строку, не начинающуюся с точки с запятой, на две подстроки. Первая подстрока до первого вхождения одного или нескольких - назначается указанной переменной цикла I, а остальная часть строки - следующей переменной цикла J в соответствии с таблицей ASCII .

Таким образом, для строк примера J содержит интересующие данные с начальным пробелом, если они не являются пустой строкой. Ведущий пробел удаляется при повторном использовании команды SET для присвоения переменной окружения Line, наконец, только строка из второго символа с индексом символа 1 до конца строки.

Но вместо использования отложенного расширения используется другая методика: для ссылки на значение переменной среды, только что установленное ранее, в командном блоке с двумя знаками процента с обеих сторон, и используйте команду CALL для принудительного использования Windows. процессор команд для анализа двух строк перед выполнением команд SET или ECHO во второй раз. Таким образом, при разборе всего блока команд перед выполнением FOR две строки с CALL стали:

call set "Line=%Line:~1%"
if defined Line call echo Line work: %Line%

Эти две строки анализируются на каждой итерации цикла во второй раз из-за команды CALL , в результате чего %Line:~1% и %Line% заменяются текущей строкой без первого символа, соответственно, полностью перед выполнением set и echo.

Интересующие строки, содержащие восклицательный знак, обрабатываются корректно этим решением из-за избежания использования отложенного расширения.

Третье решение

Третье решение аналогично второму решению. Он использует второй FOR для удаления всех начальных пробелов / табуляций из строки, назначенной переменной цикла J внешней FOR , и назначает оставшуюся строку переменной цикла L, которая может быть даже пустой строкой.

Это решение определенно лучше, чем второе, потому что оно быстрее.

Четвертое решение

Четыре решения написаны для присваивания переменной цикла I всегда всей непустой строки из захваченного вывода независимо от того, какой символ является первым символом. Поведение разделения строки отключено с определением пустого списка разделителей, а игнорирование строк, начинающихся с определенного символа, отключено с определением символа конца строки.

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

Недостаток этого решения заключается в том, что команды setlocal EnableDelayedExpansion и endlocal внутри цикла выполняют намного больше, чем просто включение и отключение отложенного расширения. См. этот ответ для получения подробной информации о командах SETLOCAL и ENDLOCAL . Так что это решение определенно не самое быстрое в наборе предоставляемых решений.

Пятый раствор

Пятое решение аналогично четвертому решению с той разницей, что оно демонстрирует общий метод, позволяющий избежать использования отложенного расширения при обработке строковых значений внутри цикла FOR с помощью подпрограммы, вызываемой из * 1178. * FOR loop.

Это решение также очень медленное, но имеет большое преимущество для упрощения отладки командного файла при запуске его с @echo ON сверху из командного файла.

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

  • call /?
  • cls /?
  • del /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...