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