如何从 Select-String 中获取捕获的组?
How to get the captured groups from Select-String?
我正在尝试使用 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 ... {...}
接下来,我看到捕获在 matches 成员中,所以我将它们取出:
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
,但它似乎 return 与上面相同。
我得到的最接近的是| 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
.
来缩短命令
看看下面的内容
$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
此脚本将从文件内容中获取正则表达式的指定捕获组,并将其匹配项输出到控制台。
$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 }
这适合我的情况。
使用文件:test.txt
// autogenerated by script
char VERSION[21] = "ABCDEFGHIJKLMNOPQRST";
char NUMBER[16] = "123456789012345";
从文件中获取 NUMBER 和 VERSION。
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
根据 Regular Expressions > Groups, Captures, and Substitutions 上的 powershell 文档:
当使用 -match
运算符时,powershell 将创建一个名为 $Matches
的 automatic variable
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
其他资源:
- 要获取多个匹配项,请参阅 How to capture multiple regex matches
- 要通过 Options/Flags,请参阅 Pass regex options to PowerShell
[regex]
type
迟到的答案,但要循环多个匹配项和组,我使用:
$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
}
我正在尝试使用 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 ... {...}
接下来,我看到捕获在 matches 成员中,所以我将它们取出:
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
,但它似乎 return 与上面相同。
我得到的最接近的是| 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
.
看看下面的内容
$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
此脚本将从文件内容中获取正则表达式的指定捕获组,并将其匹配项输出到控制台。
$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 }
这适合我的情况。
使用文件:test.txt
// autogenerated by script
char VERSION[21] = "ABCDEFGHIJKLMNOPQRST";
char NUMBER[16] = "123456789012345";
从文件中获取 NUMBER 和 VERSION。
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
根据 Regular Expressions > Groups, Captures, and Substitutions 上的 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
其他资源:
- 要获取多个匹配项,请参阅 How to capture multiple regex matches
- 要通过 Options/Flags,请参阅 Pass regex options to PowerShell
[regex]
type
迟到的答案,但要循环多个匹配项和组,我使用:
$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
}