Last active
October 24, 2022 14:56
-
-
Save JustinGrote/fc60a31b0cdf8578954bf9478eaf8f7d to your computer and use it in GitHub Desktop.
A companion to Select-String to more easily retrieve the results of capture groups, similar to $matches but pipeline friendly.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
filter Select-StringMatch { | |
<# | |
.SYNOPSIS | |
A companion to select-string to quickly fetch the value of a capture group, named or indexed | |
.DESCRIPTION | |
With -replace or -match we have the simple $matches['group'] syntax, but this doesn't really exist for Select-String | |
and the typical options are not pipeline friendly. The default object returned from Select-String is not that friendly | |
either if all you want is the value(s) of a capture group to then pipe to another command. This is basically a pipeline | |
friendly version of $matches. | |
.EXAMPLE | |
@( | |
'this part does not matter. this does a' | |
'this part does not matter. this does b' | |
'this does c. this part does not matter' | |
) | |
| Select-String 'this does .' | |
| Select-StringMatch | |
WHAT IT DOES: Fetches whatever text begins with 'this does ' followed by any character | |
------ | |
RESULT | |
------ | |
this does a | |
this does b | |
this does c | |
.EXAMPLE | |
@( | |
'this part does not matter. this does a' | |
'this part does not matter. this does b' | |
'this does c. this part does not matter' | |
) | |
| Select-String 'this does (.)' | |
| Select-StringMatch -CaptureGroup 1 | |
WHAT IT DOES: We put the letter we want in a capture group, and then fetch the first capture group. | |
------ | |
RESULT | |
------ | |
a | |
b | |
c | |
.EXAMPLE | |
@( | |
'this part does not matter. this does a' | |
'this part does not matter. this does b' | |
'this does c. this part does not matter.' | |
) | |
| Select-String 'this does (?<letter>.)' | |
| Select-StringMatch -CaptureGroup letter | |
WHAT IT DOES: Uses a named capture group 'letter' to define what we want rather than an index. | |
------ | |
RESULT | |
------ | |
a | |
b | |
c | |
.EXAMPLE | |
'first name joe','first name bob','first name frank' | |
| Select-String '(?<=first name ).+' | |
| Select-StringMatch | |
WHAT IT DOES: Uses a lookbehind to look for text that is preceded by "first name", and only return what comes after it as a capture group | |
------ | |
RESULT | |
------ | |
joe | |
bob | |
frank | |
.EXAMPLE | |
'joe franklin smith','billy william bob','jim westinghouse jones' | |
| Select-String '(?<first>\w+) (?<middle>\w+) (?<last>\w+)' | |
| Select-StringMatch 'middle' | |
WHAT IT DOES: Uses a regex to parse a name into 3 parts with capture groups, and retrieve only the middle names. | |
------ | |
RESULT | |
------ | |
franklin | |
william | |
westinghouse | |
.EXAMPLE | |
'joe franklin smith','billy william bob','jim westinghouse jones' | |
| Select-String '(?<first>\w+) (?<middle>\w+) (?<last>\w+)' | |
| Select-Object -First 1 | |
| Select-StringMatch -AsHashTable | |
WHAT IT DOES: Uses a regex to parse a name into 3 parts with capture groups, and return the first result as a hashtable. | |
The order of the hashtable keys is the order in which they appear in the regex. | |
------ | |
RESULT | |
------ | |
Name Value | |
---- ----- | |
middle franklin | |
0 joe franklin smith | |
first joe | |
last smith | |
.EXAMPLE | |
'joe franklin smith','billy william bob','jim westinghouse jones' | |
| Select-String '(?<first>\w+) (?<middle>\w+) (?<last>\w+)' | |
| Select-Object -First 1 | |
| Select-StringMatch -AsHashtable -SortHashtable | |
WHAT IT DOES: Uses a regex to parse a name into 3 parts with capture groups, and return the first result as a hashtable. | |
The order of the hashtable keys is in alphabetic order | |
------ | |
RESULT | |
------ | |
Name Value | |
---- ----- | |
0 joe franklin smith | |
first joe | |
last smith | |
middle franklin | |
.EXAMPLE | |
'joe franklin smith','billy william bob','jim westinghouse jones' | |
| Select-String '(?<first>\w+) (\w+) (?<last>\w+)' | |
| Select-Object -First 1 | |
| Select-StringMatch -AsHashtable | |
WHAT IT DOES: Demonstrates a mix of named and unnamed groups. Middle name ends up being stored as the 1st capture group as it is unnamed | |
------ | |
RESULT | |
------ | |
Name Value | |
---- ----- | |
0 joe franklin smith | |
1 franklin | |
first joe | |
last smith | |
#> | |
[CmdletBinding()] | |
param( | |
#Which capture group value to select. If not specified it will return the matched section of the string (index 0). Examples: 1 for first () capture group, 2 for second () capture group, test for named capture group (<?:test>), etc. | |
[string[]]$CaptureGroup, | |
#A list of MatchInfo objects. You should typically pipe this in from Select-String | |
[Parameter(ValueFromPipeline)][Microsoft.PowerShell.Commands.MatchInfo]$MatchInfo, | |
#If specified, returns as a hashtable of capture group values. | |
[Switch]$AsHashtable, | |
#By default, the hashtable is ordered by the occurence of the capture group in the regex. If you want then to be ordered alphabetically instead, specify this option. | |
[Switch]$SortHashtable | |
) | |
$groups = $PSItem.matches[0].Groups | |
#Return the matched string result if CaptureGroup is not specified | |
$result = if ($CaptureGroup.count -eq 0 ) { | |
if ($AsHashtable) { | |
$groups | |
} else { | |
$groups[0] | |
} | |
} else { | |
foreach ($key in $CaptureGroup) { | |
if ($groups.containsKey($key)) { | |
$groups[$key] | |
} | |
} | |
} | |
if ($AsHashtable) { | |
$groupHashtable = [ordered]@{} | |
if ($SortHashtable) {$result = Sort-Object -InputObject $result -Property Name} | |
foreach ($groupItem in $result) { | |
$groupHashtable[$groupItem.Name] = $groupItem.Value | |
} | |
return $groupHashtable | |
} | |
return $result.Value | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment