如何从选择字符串中获取捕获的组?


69

我正在尝试使用Powershell(版本4)从Windows上的一组文件中提取文本:

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

到现在为止还挺好。这给出了一组不错的MatchInfo对象:

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

接下来,我看到捕获在matchs成员中,因此我将它们取出:

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)给出了相同的结果。

我想补充一点,在进一步尝试后,似乎可以通过删除piped来缩短命令| Select-Object -Property Groups


1
每个匹配项都有一个隐式组0,它本身就是一个匹配项。因此,在您的案例Groups集合中,有两个元素:匹配自身和第一个捕获组。如果只想捕获组,则必须通过指定Groups[1]
user4003407

Answers:


69

看看以下

$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

没有前导空格,星号不会显示在答案第二行(您分配给的位置$a)的捕获组中。我尝试编辑,但是由于我的编辑少于六个字符而出现错误。IOW,捕获组显示为(.)不是(.*)您想要的。
马克·谢尔曼

最后一条语句中的%{“”}语法是什么?
Koja

2
%是的别名ForEach-Object。那么您可以使用处理每个对象$_
JPBlanc

7

根据关于正则表达式>组,捕获和替换的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

其他资源


1

这适合我的情况。

使用文件: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


1

答案较晚,但是要循环使用多个匹配项和组,请使用:

$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
}

-1

该脚本将从文件的内容中获取正则表达式的指定捕获组,并将其匹配项输出到控制台。


$file是您要加载的文件是您要
$cg捕获的捕获组
$regex是正则表达式模式



示例文件及其要加载的内容:

C:\ some \ 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 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.