Tuesday, January 24, 2012

Named Groups in Regular Expressions

I don't know how I went this long without discovering named groups in regular expressions, but I'm genuinely excited about them (yes, I'm a nerd).

A quick recap of the most common way to use regular expressions in PowerShell. Let's say I have a string like the one below (sorry it isn't a more simple example, but this is literally something I ran into today).  I got it by querying the local administrators of a system using SCCM.  The problem is, I want it in domain\user format.


My first thought was to do something like this:

$string -match '(?<=domain\=")([^"]+).*(?<=name\=")([^"]+)'

It evaluates to True on my test string, so I go look at $matches:


Name                           Value
----                           -----
2                              adminuser
1                              MYDOMAIN
0                              MYDOMAIN",Name="adminuser

Okay, I've captured my groups, but I notice something strange.  Why is $matches a hashtable instead of an array?  Because of named groups, that's why.

To create a named group, you put the parentheses around it just like normal, but you add
'?<groupname>' to the beginning of the capture.  This stores the group under the name 'groupname'.  Let's try that with the above example:

$string -match '(?<=domain\=")(?<domain>[^"]+).*(?<=name\=")(?<name>[^"]+)'


Name                           Value
----                           -----
name                           adminuser
domain                         MYDOMAIN
0                              MYDOMAIN",Name="adminuser

It makes my regex a little longer, but it is so much easier now when I go to use the values I've collected to remember $matches.domain and $matches.name instead of $matches[1] and $matches[2].


Anonymous said...

What version powershell are you using? This does not work with powershell 3.0

Roman Revell said...

Thanks! That's the exact problem I'm trying to solve.