Вопрос или проблема
Я хотел бы создать регулярное выражение, которое соответствует следующим критериям, и я использую функцию Select-String в PowerShell. У меня есть этот запрос, и я хочу получить все варианты параметров (то есть часть, начинающуюся с @PAR) между определенной частью запроса, где часть #KEINERW отсутствует. Проблема в том, что, когда я тестирую это в regex101 или запускаю свой скрипт (результат тот же), версия с #KEINERW также совпадает, чего не должно быть.
Вот соответствующая часть запроса:
INSERT INTO #BASIS_VARIABLEN
select ''tagid'' as ParameterTyp,IdentCode as Variable
from R34_META_DELIVERY.zeit.Tag t
where 1=1 '+dbo.SVF_GetAuswahlEinschraenkung('t.IdentCode',@PAR_MONAT_Stichtag)+'
INSERT INTO #BASIS_VARIABLEN
select ''bankid'' as ParameterTyp,BLZ as Variable
from R34_ZDW.orga.Bank t
where 1=1 '+dbo.SVF_GetAuswahlEinschraenkung('t.BLZ',@PAR_BLZ)
INSERT INTO #BASIS_VARIABLEN
select ''segmentid'' as ParameterTyp,Segment as Variable
from R34_ZDW.orga.Bank t
where 1=1 '+dbo.SVF_GetAuswahlEinschraenkung('t.Segment',@PAR#KEINERW_SEG_Segment)
EXEC sp_executesql @sql
И я хотел бы получить только эту часть:
INSERT INTO #BASIS_VARIABLEN
select ''tagid'' as ParameterTyp,IdentCode as Variable
from R34_META_DELIVERY.zeit.Tag t
where 1=1 '+dbo.SVF_GetAuswahlEinschraenkung('t.IdentCode',@PAR_MONAT_Stichtag)+'
INSERT INTO #BASIS_VARIABLEN
select ''bankid'' as ParameterTyp,BLZ as Variable
from R34_ZDW.orga.Bank t
where 1=1 '+dbo.SVF_GetAuswahlEinschraenkung('t.BLZ',@PAR_BLZ)
EXEC sp_executesql @sql
Он не исключит часть:
INSERT INTO #BASIS_VARIABLEN
select ''segmentid'' as ParameterTyp,Segment as Variable
from R34_ZDW.orga.Bank t
where 1=1 '+dbo.SVF_GetAuswahlEinschraenkung('t.Segment',@PAR#KEINERW_SEG_Segment)
Это мой скрипт, который я создал, есть идеи, как его исправить, чтобы получить правильный результат? Самое главное, я должен использовать регулярное выражение и меньше программной логики, отсюда моя трудность. Я мог бы решить это с помощью -raw и индексов, но регулярное выражение должно быть повторно используемым в других языках. Вот мой полный PSScript:
$OutputFile = "C:\Users\WRSKOI\Documents\Check_USP_VW\outfile.txt"
$ErrorFile = "C:\Users\WRSKOI\Documents\Check_USP_VW\errorfile.txt"
# Создать или перезаписать выходные и ошибочные файлы
New-Item -ItemType File -Path $OutputFile -Force | Out-Null
New-Item -ItemType File -Path $ErrorFile -Force | Out-Null
# Определить шаблон regex для поиска параметров (с поддержкой многострочности с использованием '(?s)')
$RegexPattern = "(?s)INSERT\sINTO\s#BASIS_VARIABLEN.*?@PAR_(?!#KEINERW)(?:TAG|MONAT|DATUM|DATUMVONBIS|BLZ|SEG|BER|GES|MAR|SPR|KSG|KST|REF|TEXT|KTO|TEXTAREA)[\w-]*.*?EXEC\s+sp_executesql\s+@sql"
# Получить все .txt файлы в указанной директории (рекурсивно)
Get-ChildItem -Path "C:\Users\WRSKOI\Documents\Check_USP_VW\TestUSP" -Filter "*.txt" -Recurse | ForEach-Object {
try {
$File = $_.FullName
# Прочитать весь файл как одну строку для многострочного поиска regex
$FileContent = Get-Content -Path $File -Raw
# Использовать Select-String для поиска многострочного шаблона в содержимом
$Matches = [regex]::Matches($FileContent, $RegexPattern)
# Если найдены совпадения, записать их в выходной файл
if ($Matches) {
foreach ($Match in $Matches) {
$LineNumber = ($FileContent.Substring(0, $Match.Index).Split("`n").Count) # Вычислить номер строки
$Output = "File: $File, Line: $LineNumber, Match: $($Match.Value)"
Add-Content -Path $OutputFile -Value $Output
}
}
}
catch {
# Записать любые исключения в файл ошибок
$_.Exception.Message | Add-Content -Path $ErrorFile
}
}
Ответ или решение
Для решения вашей проблемы с использованием регулярных выражений и исключением вхождений с "#KEINERW", вам нужно внести некоторые изменения в регулярное выражение.
Во-первых, давайте разберем ваш исходный шаблон регулярного выражения:
(?s)INSERT\sINTO\s#BASIS_VARIABLEN.*?@PAR_(?!#KEINERW)(?:TAG|MONAT|DATUM|DATUMVONBIS|BLZ|SEG|BER|GES|MAR|SPR|KSG|KST|REF|TEXT|KTO|TEXTAREA)[\w-]*.*?EXEC\s+sp_executesql\s+@sql
Ключевое здесь – использование негативного заранее заданного выражения (?!#KEINERW)
, которое говорит регулярному выражению не соответствовать шестизначному коду, если он начинается с @PAR#KEINERW
. Однако проблема в том, что это негативное предшествующее выражение срабатывает только на следующем символе, поэтому регулярное выражение все равно может захватывать строки, где используется @PAR#KEINERW
.
Чтобы решить данную проблему, нужно изменить подход, чтобы отфильтровать строки, содержащие #KEINERW
, на более высоком уровне. Вот измененный шаблон:
(?s)INSERT\sINTO\s#BASIS_VARIABLEN(?:(?!#KEINERW).)*?@PAR_(?:TAG|MONAT|DATUM|DATUMVONBIS|BLZ|SEG|BER|GES|MAR|SPR|KSG|KST|REF|TEXT|KTO|TEXTAREA)[\w-]*.*?EXEC\s+sp_executesql\s+@sql
Обратите внимание на изменения:
- Мы добавили
(?:(?!#KEINERW).)*?
, что позволяет нам проверить, что строка не содержит последовательности#KEINERW
до тех пор, пока не достигнем нужного паттерна.
Теперь ваш скрипт будет выглядеть следующим образом:
$OutputFile = "C:\Users\WRSKOI\Documents\Check_USP_VW\outfile.txt"
$ErrorFile = "C:\Users\WRSKOI\Documents\Check_USP_VW\errorfile.txt"
# Создание или перезапись файлов вывода и ошибок
New-Item -ItemType File -Path $OutputFile -Force | Out-Null
New-Item -ItemType File -Path $ErrorFile -Force | Out-Null
# Определение шаблона regex для соответствия параметрам с поддержкой многострочного режима '(?s)'
$RegexPattern = "(?s)INSERT\sINTO\s#BASIS_VARIABLEN(?:(?!#KEINERW).)*?@PAR_(?:TAG|MONAT|DATUM|DATUMVONBIS|BLZ|SEG|BER|GES|MAR|SPR|KSG|KST|REF|TEXT|KTO|TEXTAREA)[\w-]*.*?EXEC\s+sp_executesql\s+@sql"
# Получение всех .txt файлов в указанной директории (рекурсивно)
Get-ChildItem -Path "C:\Users\WRSKOI\Documents\Check_USP_VW\TestUSP" -Filter "*.txt" -Recurse | ForEach-Object {
try {
$File = $_.FullName
# Чтение всего файла как одной строки для многострочного соответствия regex
$FileContent = Get-Content -Path $File -Raw
# Использование Select-String для поиска многострочного шаблона в содержимом
$Matches = [regex]::Matches($FileContent, $RegexPattern)
# Если найдены совпадения, записать их в файл вывода
if ($Matches) {
foreach ($Match in $Matches) {
$LineNumber = ($FileContent.Substring(0, $Match.Index).Split("`n").Count) # Расчет номера строки
$Output = "File: $File, Line: $LineNumber, Match: $($Match.Value)"
Add-Content -Path $OutputFile -Value $Output
}
}
}
catch {
# Запись любых исключений в файл ошибок
$_.Exception.Message | Add-Content -Path $ErrorFile
}
}
Попробуйте запустить этот скрипт. Он должен исключить части, содержащие #KEINERW
, и возвращать только нужные вам параметры.