it-source

구성 블록과 일치하는 다중 행 정규식

criticalcode 2023. 8. 24. 22:11
반응형

구성 블록과 일치하는 다중 행 정규식

파일의 특정 구성 블록(여러 구성 블록)을 일치시키는 데 문제가 있습니다.다음은 구성 파일에서 추출하려는 블록입니다.

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

반응형