Share via

Named captures problem

YaroC 321 Reputation points
2023-09-13T13:08:57.09+00:00

Having log like the quoted line below below, trying to experiment with regex, which I usually avoid when possible, but hey, one has to learn one day. I trying to group matches I'm intrested in. So I tested as below. Which gives me nice groups, however, when combining all the regex in one line, I don't get the matches. What am I missing here? Oh and yes, tried CHatGTP and failed miserably.

$log = "sthg... 0.003789567 PTP(10.156.210.14:12,unicast,telecom) -0.001123234"
[regex]$proto = '(?<protocol>PTP)'
[regex]$IP = '(?<IP>(\d{1,3}(\.)?){4}(?=:))'
[regex]$type = '(?<type>(?<=\,).*(?=\,))' 
$proto.Matches($log)
$IP.Matches($log)
$type.Matches($log)
[regex]$test = '(?<protocol>PTP)(?<IP>(\d{1,3}(\.)?){4}(?=:))(?<type>(?<=\,).*(?=\,))'
Windows for business | Windows Server | User experience | PowerShell

1 answer

Sort by: Most helpful
  1. Rich Matheisen 48,116 Reputation points
    2023-09-13T21:45:25.31+00:00

    Regex's are a language all their own. Yours looks to work okay on the limited data you offered to test it with. If this were a Perl forum I wouldn't offer this opinion, but this is PowerShell and there are many people that read this forum that do not understand regex. You may also find that any code you write that uses a complex regex will befuddle someone that has to maintain your code (and it may befuddle you, too, years from now). For a complex regex it might be beneficial to use the "#" option to document what's going on in the regex.

    Another (simpler) approach might be to extract two groups from the string. The first would be "PTP" and the next would be everything within the parentheses. Split the 2nd group on the commas. Then split the 1st result of the split on the ":". Most people understand string manipulation far better than regular expressions.

    All of the above is just my opinion. Your code works.

    Here's an expansion of your code to produce a PowerShell object that holds the name/value pairs of the named groups in a way that allows you to do any further work on it using a CSV (if you choose to export the output in that format).

    $log =  "sthg... 0.003789567 PTP(10.156.210.14:12,unicast,telecom) -0.001123234",
            "sthg... 0.003789567 PTP(10.156.210.15:12,multicast,telecom) -0.001123234"
    
    [regex]$test = '(?<protocol>PTP)\((?<IP>(\d{1,3}(\.)?){4}(?=:)):\d+\,(?<type>(?<=\,).*(?=\,))'
    
    $h = [ordered]@{}
    $namefound = $false
    $log |
        ForEach-Object {
            ForEach ($group in $test.Matches($_).groups) {
                if ($group.name -match '\D+') {
                    $namefound = $true
                    $h[$group.Name] = $group.Value
                }
            }
            if ($namefound) {
                [PSCustomObject]$h
                $namefound = $false
                $h.Clear()
            }
        }
    

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.