Как получить захваченные группы из Select-String?

Я пытаюсь извлечь текст из набора файлов в Windows, используя Powershell (версия 4):

PS > Select-String -AllMatches -Pattern <mypattern-with(capture)> -Path file.jsp | Format-Table

Все идет нормально. Это дает хороший набор MatchInfo объекты:

IgnoreCase                    LineNumber Line                          Filename                      Pattern                       Matches
----------                    ---------- ----                          --------                      -------                       -------
    True                            30   ...                           file.jsp                      ...                           {...}

Далее я вижу, что захваты находятся в матче участника, поэтому вынимаю их:

PS > Select-String -AllMatches -Pattern <mypattern-with(capture)> -Path file.jsp | ForEach-Object -MemberName Matches | Format-Table

Который дает:

Groups        Success Captures                 Index     Length Value
------        ------- --------                 -----     ------ -----
{...}         True    {...}                    49        47     ...

или как список с | Format-List:

Groups   : {matched text, captured group}
Success  : True
Captures : {matched text}
Index    : 39
Length   : 33
Value    : matched text

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

Я пытался добавить еще | ForEach-Object -MemberName Groups, но, похоже, возвращает то же самое, что и выше.

Самый близкий, который я получаю, с | Select-Object -Property Groups что действительно дает мне то, что я ожидал (список наборов):

Groups
------
{matched text, captured group}
{matched text, captured group}
...

Но тогда я не могу извлечь захваченную группу из каждого из них, я попытался с | Select-Object -Index 1 Я получаю только один из этих наборов.


Обновление: возможное решение

Кажется, что, добавив | ForEach-Object { $_.Groups.Groups[1].Value } Я получил то, что искал, но не понимаю, почему - поэтому я не уверен, что смогу получить правильный результат при распространении этого метода на целые наборы файлов.

Почему это работает?

Как примечание, это | ForEach-Object { $_.Groups[1].Value } (т.е. без второго .Groups) дает тот же результат.

Я хотел бы добавить, что при дальнейших попытках кажется, что команда может быть сокращена путем удаления | Select-Object -Property Groups,

1 ответ

Решение

Посмотрите на следующее

$a = "http://192.168.3.114:8080/compierews/" | Select-String -Pattern '^http://(.*):8080/(.*)/$' 

$a сейчас MatchInfo ($a.gettype()) оно содержит Matches имущество.

PS ps:\> $a.Matches
Groups   : {http://192.168.3.114:8080/compierews/, 192.168.3.114, compierews}
Success  : True
Captures : {http://192.168.3.114:8080/compierews/}
Index    : 0
Length   : 37
Value    : http://192.168.3.114:8080/compierews/

в группе участники вы найдете то, что вы ищете, так что вы можете написать:

"http://192.168.3.114:8080/compierews/" | Select-String -Pattern '^http://(.*):8080/(.*)/$'  | % {"IP is $($_.matches.groups[1]) and path is $($_.matches.groups[2])"}

IP is 192.168.3.114 and path is compierews

Согласно документам PowerShell Регулярные выражения> Группы, захваты и замены:

При использовании -matchоператор, powershell создаст автоматическую переменную с именем$Matches

PS> "The last logged on user was CONTOSO\jsmith" -match "(.+was )(.+)"

Значение, возвращаемое из этого выражения, просто true|false, но PS добавит $Matches хеш-таблица

Итак, если вы выведете $Matches, вы получите все группы захвата:

PS> $Matches

Name     Value
----     -----
2        CONTOSO\jsmith
1        The last logged on user was
0        The last logged on user was CONTOSO\jsmith

И вы можете получить доступ к каждой группе захвата индивидуально с помощью точечной записи, например:

PS> "The last logged on user was CONTOSO\jsmith" -match "(.+was )(.+)"
PS> $Matches.2
CONTOSO\jsmith

Дополнительные ресурсы:

Поздний ответ, но для зацикливания нескольких совпадений и групп я использую:

$pattern = "Login:\s*([^\s]+)\s*Password:\s*([^\s]+)\s*"
$matches = [regex]::Matches($input_string, $pattern)

foreach ($match in $matches)
{
    Write-Host  $match.Groups[1].Value
    Write-Host  $match.Groups[2].Value
}

Это сработало в моей ситуации.

Используя файл: test.txt

// autogenerated by script
char VERSION[21] = "ABCDEFGHIJKLMNOPQRST";
char NUMBER[16] = "123456789012345";

Получите НОМЕР и ВЕРСИЮ из файла.

PS C:\> Select-String -Path test.txt -Pattern 'VERSION\[\d+\]\s=\s\"(.*)\"' | %{$_.Matches.Groups[
1].value}

ABCDEFGHIJKLMNOPQRST

PS C:\> Select-String -Path test.txt -Pattern 'NUMBER\[\d+\]\s=\s\"(.*)\"' | %{$_.Matches.Groups[1
].value}

123456789012345

Этот скрипт извлекает указанную группу захвата регулярного выражения из содержимого файла и выводит ее совпадения на консоль.


$file это файл, который вы хотите загрузить
$cg это группа захвата, которую вы хотите захватить
$regex шаблон регулярного выражения



Пример файла и его содержимое для загрузки:

C: \ некоторые \file.txt

This is the especially special text in the file.



Пример использования: .\get_regex_capture.ps1 -file "C:\some\file.txt" -cg 1 -regex '\b(special\W\w+)'

Выход: special text


get_regex_capture.ps1

Param(
    $file=$file,
    [int]$cg=[int]$cg,
    $regex=$regex
)
[int]$capture_group = $cg
$file_content = [string]::Join("`r`n", (Get-Content -Raw "$file"));
Select-String -InputObject $file_content -Pattern $regex -AllMatches | % { $_.Matches.Captures } | % { echo $_.Groups[$capture_group].Value }
Другие вопросы по тегам