구성 블록과 일치하는 다중 행 정규식
파일의 특정 구성 블록(여러 구성 블록)을 일치시키는 데 문제가 있습니다.다음은 구성 파일에서 추출하려는 블록입니다.
ap71xx 00-01-23-45-67-89
use profile PROFILE
use rf-domain DOMAIN
hostname ACCESSPOINT
area inside
!
이와 같은 MAC 주소가 각각 다른 여러 개 있습니다.여러 줄에 걸쳐 구성 블록을 일치시키려면 어떻게 해야 합니까?
첫 번째 문제는 여러 줄에 걸쳐 일치시키려면 파일 내용을 개별 줄이 아닌 단일 문자열로 처리해야 한다는 것입니다.예를 들어, Get-Content를 사용하여 파일의 내용을 읽을 경우 기본적으로 문자열 배열(각 줄에 하나의 요소)이 제공됩니다.여러 줄에 걸쳐 일치시키려면 파일을 단일 문자열로 지정하고 파일이 너무 크지 않아야 합니다.이렇게 할 수 있습니다.
$fileContent = [io.file]::ReadAllText("C:\file.txt")
3에서 "PowerShell 3.0" Get-Content"와 함께 할 수 .-Raw
매개변수:
$fileContent = Get-Content c:\file.txt -Raw
그런 다음 여러 줄에 걸쳐 일치하는 정규식 옵션을 지정해야 합니다.
- 라인 모드단일 라인 모드)
.
라인 피드를 포함한 모든 문자와 일치) 및 - 모드Multiline mode)
^
그리고.$
포함된 라인 종결자 일치), 예: (?smi)
는 대소문자 "i"를 입니다.
예:
C:\> $fileContent | Select-String '(?smi)([0-9a-f]{2}(-|\s*$)){6}.*?!' -AllMatches |
Foreach {$_.Matches} | Foreach {$_.Value}
00-01-23-45-67-89
use profile PROFILE
use rf-domain DOMAIN
hostname ACCESSPOINT
area inside
!
00-01-23-45-67-89
use profile PROFILE
use rf-domain DOMAIN
hostname ACCESSPOINT
area inside
!
을 합니다.Select-String
할 수 을 수행할 cmdlet-AllMatches
그리고 그것은 모든 매치를 출력할 것이고 반면에.-match
연산자가 첫 번째 일치 후에 멈춥니다.일치하는 항목이 있는지 확인하기만 하면 되는 부울 연산자이기 때문에 의미가 있습니다.
이것이 누군가에게 여전히 가치가 있을 수 있고 실제 요구 사항에 따라 키스의 대답에 있는 정규식은 그렇게 복잡할 필요가 없습니다.사용자가 각 블록을 단순히 출력하려는 경우 다음과 같이 하면 됩니다.
$fileContent = [io.file]::ReadAllText("c:\file.txt")
$fileContent |
Select-String '(?smi)ap71xx[^!]+!' -AllMatches |
%{ $_.Matches } |
%{ $_.Value }
ap71xx[^!]*!
를 낼 이고, 더나성의사용을 할 것입니다..*
정규식은 예기치 않은 결과를 생성할 수 있으므로 권장되지 않습니다. 턴[^!]+!
느낌표와 느낌표를 제외한 모든 문자와 일치합니다.
출력에 블록 시작이 필요하지 않은 경우 업데이트된 스크립트는 다음과 같습니다.
$fileContent |
Select-String '(?smi)ap71xx([^!]+!)' -AllMatches |
%{ $_.Matches } |
%{ $_.Groups[1] } |
%{ $_.Value }
Groups[0]
에는 일치하는 문자열인 하는전문포을함자다니합이 됩니다.Groups[1]
정규식의 괄호 안에 일치하는 문자열을 포함합니다.
한다면$fileContent
추가 처리에 필요하지 않으므로 변수를 제거할 수 있습니다.
[io.file]::ReadAllText("c:\file.txt") |
Select-String '(?smi)ap71xx([^!]+!)' -AllMatches |
%{ $_.Matches } |
%{ $_.Groups[1] } |
%{ $_.Value }
이 정규식은 텍스트를 검색합니다.ap
그 뒤에는 임의의 수의 문자와 새로운 행이 뒤따릅니다.!
:
(?si)(a).+?\!{1}
그래서 저는 조금 지루했습니다.나는 당신이 설명한 대로 텍스트 파일을 분해하는 스크립트를 작성했습니다(표시한 줄만 포함되어 있는 경우).ap, 프로필, 도메인, 호스트 이름 또는 영역과 같은 키워드를 포함하지 않는 한 다른 임의의 행과 함께 작동할 수 있습니다.이를 가져오고 각 속성(MAC, 프로파일, 도메인, 호스트 이름, 영역)에 대해 한 줄씩 확인한 다음 나중에 사용할 수 있는 개체에 배치합니다.이것이 당신이 요청한 것이 아니라는 것을 알지만, 제가 그것을 작업하는 데 시간을 썼기 때문에, 그것이 어떤 도움이 될 수 있기를 바랍니다.관심 있는 사람이 있다면 여기 대본이 있습니다.특정 요구 사항에 맞게 조정해야 합니다.
$Lines = Get-Content "c:\test\test.txt"
$varObjs = @()
for ($num = 0; $num -lt $lines.Count; $num =$varLast ) {
#Checks to make sure the line isn't blank or a !. If it is, it skips to next line
if ($Lines[$num] -match "!") {
$varLast++
continue
}
if (([regex]::Match($Lines[$num],"^\s.*$")).success) {
$varLast++
continue
}
$Index = [array]::IndexOf($lines, $lines[$num])
$b=0
$varObj = New-Object System.Object
while ($Lines[$num + $b] -notmatch "!" ) {
#Checks line by line to see what it matches, adds to the $varObj when it finds what it wants.
if ($Lines[$num + $b] -match "ap") { $varObj | Add-Member -MemberType NoteProperty -Name Mac -Value $([regex]::Split($lines[$num + $b],"\s"))[1] }
if ($lines[$num + $b] -match "profile") { $varObj | Add-Member -MemberType NoteProperty -Name Profile -Value $([regex]::Split($lines[$num + $b],"\s"))[3] }
if ($Lines[$num + $b] -match "domain") { $varObj | Add-Member -MemberType NoteProperty -Name rf-domain -Value $([regex]::Split($lines[$num + $b],"\s"))[3] }
if ($Lines[$num + $b] -match "hostname") { $varObj | Add-Member -MemberType NoteProperty -Name hostname -Value $([regex]::Split($lines[$num + $b],"\s"))[2] }
if ($Lines[$num + $b] -match "area") { $varObj | Add-Member -MemberType NoteProperty -Name area -Value $([regex]::Split($lines[$num + $b],"\s"))[2] }
$b ++
} #end While
#Adds the $varObj to $varObjs for future use
$varObjs += $varObj
$varLast = ($b + $Index) + 2
}#End for ($num = 0; $num -lt $lines.Count; $num = $varLast)
#displays the $varObjs
$varObjs
제가 보기에 매우 깨끗하고 간단한 접근 방식은 다음과 같이 명명된 캡처와 함께 여러 줄의 블록 정규식을 사용하는 것입니다.
# Based on this text configuration:
$configurationText = @"
ap71xx 00-01-23-45-67-89
use profile PROFILE
use rf-domain DOMAIN
hostname ACCESSPOINT
area inside
!
"@
# We can build a multiline regex bloc with the strings to be captured.
# Here, i am using the regex '.*?' than roughly means 'capture anything, as less as possible'
# A more specific regex can be defined for each field to capture.
# ( ) in the regex if for defining a group
# ?<> is for naming a group
$regex = @"
(?<userId>.*?) (?<userCode>.*?)
use profile (?<userProfile>.*?)
use rf-domain (?<userDomain>.*?)
hostname (?<hostname>.*?)
area (?<area>.*?)
!
"@
# Lets see if this matches !
if($configurationText -match $regex)
{
# it does !
Write-Host "Config text is successfully matched, here are the matches:"
$Matches
}
else
{
Write-Host "Config text could not be matched."
}
이 스크립트는 다음을 출력합니다.
PS C:\Users\xdelecroix> C:\FusionInvest\powershell\regex-capture-multiline-stackoverflow.ps1
Config text is successfully matched, here are the matches:
Name Value
---- -----
hostname ACCESSPOINT
userProfile PROFILE
userCode 00-01-23-45-67-89
area inside
userId ap71xx
userDomain DOMAIN
0 ap71xx 00-01-23-45-67-89...
좀 더 유연하게 하려면 -match 대신 Select-String을 사용할 수 있지만 이 예제의 맥락에서 이는 그다지 중요하지 않습니다.
제 생각은 이렇습니다.정규식이 필요하지 않으면 -like 또는 .contains()를 사용할 수 있습니다.이 질문은 검색 패턴이 무엇인지 절대 말하지 않습니다.다음은 Windows 텍스트 파일의 예입니다.
$file = (get-content -raw file.txt) -replace "`r" # avoid the line ending issue
$pattern = 'two
three
f.*' -replace "`r"
# just showing what they really are
$file -replace "`r",'\r' -replace "`n",'\n'
$pattern -replace "`r",'\r' -replace "`n",'\n'
$file -match $pattern
$file | select-string $pattern -quiet
언급URL : https://stackoverflow.com/questions/12572164/multiline-regex-to-match-config-block
'it-source' 카테고리의 다른 글
ES6 구문을 사용하여 jquery를 가져오는 방법은 무엇입니까? (0) | 2023.08.24 |
---|---|
스프링 배치 프레임워크 - 배치 테이블 자동 생성 (0) | 2023.08.24 |
모든 Ajax 호출 후 Google 차트 다시 그리기 (0) | 2023.08.24 |
오른쪽에서 CSS 배경 이미지 x 픽셀을 배치하시겠습니까? (0) | 2023.08.24 |
UNION ALL은 결과 집합의 순서를 보장합니까? (0) | 2023.08.24 |