regex - символов - регулярные выражения шпаргалка




Многострочное регулярное выражение для соответствия блоку конфигурации (2)

У меня возникли некоторые проблемы при попытке сопоставить определенный блок конфигурации (несколько) из файла. Ниже приведен блок, который я пытаюсь извлечь из файла конфигурации:

ap71xx 00-01-23-45-67-89
 use profile PROFILE
 use rf-domain DOMAIN
 hostname ACCESSPOINT
 area inside
!

Есть несколько таких же, каждый с разным MAC-адресом. Как мне сопоставить блок конфигурации в нескольких строках?


В случае, если это все еще может иметь значение для кого-то и в зависимости от фактического требования, регулярное выражение в ответе Кейта не должно быть таким сложным. Если пользователь просто хочет вывести каждый блок, будет достаточно следующего:

$fileContent = [io.file]::ReadAllText("c:\file.txt")
$fileContent |
    Select-String '(?smi)ap71xx[^!]+!' -AllMatches |
    %{ $_.Matches } |
    %{ $_.Value }

ap71xx[^!]*! выражение ap71xx[^!]*! будет работать лучше, и использование .* в регулярном выражении не рекомендуется, потому что это может привести к неожиданным результатам. Шаблон [^!]+! будет соответствовать любому символу, кроме восклицательного знака, за которым следует восклицательный знак.

Если начало вывода не требуется в выводе, обновленный скрипт:

$fileContent |
    Select-String '(?smi)ap71xx([^!]+!)' -AllMatches |
    %{ $_.Matches } |
    %{ $_.Groups[1] } |
    %{ $_.Value }

Groups[0] содержит всю совпавшую строку, Groups[1] будет содержать совпадение строк в скобках в регулярном выражении.

Если $fileContent не требуется для дальнейшей обработки, переменная может быть $fileContent :

[io.file]::ReadAllText("c:\file.txt") |
    Select-String '(?smi)ap71xx([^!]+!)' -AllMatches |
    %{ $_.Matches } |
    %{ $_.Groups[1] } |
    %{ $_.Value }

Первая проблема, с которой вы можете столкнуться, состоит в том, что для сопоставления по нескольким строкам вам необходимо обрабатывать содержимое файла как одну строку, а не по отдельной строке. Например, если вы используете Get-Content для чтения содержимого файла, то по умолчанию он выдаст вам массив строк - по одному элементу для каждой строки. Чтобы найти соответствие между строками, вы хотите, чтобы файл был в одной строке (и, надеюсь, файл не слишком большой). Вы можете сделать это так:

$fileContent = [io.file]::ReadAllText("C:\file.txt")

Или в PowerShell 3.0 вы можете использовать Get-Content с параметром -Raw :

$fileContent = Get-Content c:\file.txt -Raw

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

  • Режим SingleLine ( . Соответствует любому символу, включая перевод строки), а также
  • Многострочный режим ( ^ и $ соответствуют встроенным ограничителям строки), например
  • (?smi) - обратите внимание, «я» означает игнорировать регистр

например:

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 для поиска, потому что вы можете указать -AllMatches и он будет выводить все совпадения, тогда как оператор -match останавливается после первого совпадения. Имеет смысл, потому что это логический оператор, который просто должен определить, есть ли совпадение.





powershell