?
Solved

Powershell regular expression problem

Posted on 2011-02-17
12
Medium Priority
?
1,149 Views
Last Modified: 2012-05-11
I have a regular Expression challenge.
In the code that I've added, I anticipate two not identical matches, but instead I get two identical matches:

Expected Output:
Name Value  
---- -----  
1    00:00:03
0    09:40:23

Actual output:
Name Value  
---- -----  
1    09:40:23
0    09:40:23

Can anyone explain why this happens, and in this help me pass Saint Peter.

Thank you!
Anders
$string = "(09:40:23)(00:00:03)" 

#$string = "(00:00:03)" # Using this returns one match, so the regular expression is not totally wasted

$string -match "([0-3][0-9]:[0-5][0-9]:[0-5][0-9])" |Out-Null
$matches |ft -autosize

Open in new window

0
Comment
Question by:jmateknik
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
12 Comments
 
LVL 17

Expert Comment

by:Shinesh Premrajan
ID: 34915099
Now sure how powershell works, i find that since its a string, the multiple matches could be defined as

"([0-3][0-9]:[0-5][0-9]:[0-5][0-9])+"

Hope this helps
0
 
LVL 16

Expert Comment

by:sjklein42
ID: 34915195
It may not help but I don't think you need the parens in the pattern on line 5.

$string -match "[0-3][0-9]:[0-5][0-9]:[0-5][0-9]" |Out-Null

Open in new window

0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34915797
The reason you see two "matches" is due to the parentheses. If you'll notice, there should be a number preceding the match (see screenshot). This number refers to the "capture group" the match belongs to. Zero represents the overall match, and one refers to the first capture group, which you set when you included the parentheses. PS shows you both groups. Removing the parentheses results in only the overall match (group 0) being displayed (2nd execution in screenshot).
Untitled.png
0
Are your AD admin tools letting you down?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34915864
As further explanation, the more capturing parentheses you add, the more groups that will show up. Doubling-up the parentheses will result in 3 identical "matches" (first execution below). Shifting the parentheses around, however, will give you different results (second execution).
Untitled.png
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34915873
Here was the script for the execution above:

Execution 1
$string = "(09:40:23)(00:00:03)" 

#$string = "(00:00:03)" # Using this returns one match, so the regular expression is not totally wasted

$string -match "(([0-3][0-9]:[0-5][0-9]:[0-5][0-9]))" |Out-Null
$matches |ft -autosize

Open in new window



Execution 2
$string = "(09:40:23)(00:00:03)" 

#$string = "(00:00:03)" # Using this returns one match, so the regular expression is not totally wasted

$string -match "([0-3][0-9]):([0-5][0-9]):[0-5][0-9]" |Out-Null
$matches |ft -autosize

Open in new window

0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34916247
One last thing  = )


I think you may have been trying to match the parentheses which are part of your data. What you need to be aware of is that parentheses have special meaning (as mentioned above) within regex; as such, you need to "escape" them (by using a preceding backslash) when you want them to be matched as a literal character. Here is a modified version of your pattern which would match the parentheses:
$string -match "\([0-3][0-9]:[0-5][0-9]:[0-5][0-9]\)" |Out-Null

Open in new window

0
 
LVL 1

Author Comment

by:jmateknik
ID: 34916584
shinuq and sjklein42:
Thanks for your suggestions but it didn't solve it.

kaufmed:
Thanks for pulling your energy in the project.
I understand your explanation to the grouping/how to use parentheses.

I regret having used parenthesis in the search-string, which gives the impression that I want to capture the time-value WITH the parentheses. Putting the parentheses in the regular expression was merely my own process towards a solution to capture both values/I am aware that capturing the parentheses themselves will need "escaping".

The core-challenge remains unsolved:
How do I capture both time-values ['09:40:23' (being an uninteresting time-value) and '00:00:03' (being a timespan and the value i actually need to get hold of) ].

As pointed in my out-commented line in my first code-example: if the search-string (for testing) only consists of the second value ['00:00:03'] , that value is indeed captured by the regular expression presented, so it might just be a slight correction to the regular expression, something like telling the regular expression to be greedy.
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34916994
I am by no means a PS guru, but I believe -match only confirms the first match, if any. There may be a more efficient way to do what you want, but what I am familiar with would be something like:
$string = "(09:40:23)(00:00:03)" 

#$string = "(00:00:03)" # Using this returns one match, so the regular expression is not totally wasted

$matches = [System.Text.RegularExpressions.Regex]::Matches($string, "[0-3][0-9]:[0-5][0-9]:[0-5][0-9]")

$matches |ft -autosize

Open in new window

0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 2000 total points
ID: 34917226
Here's one that's a bit more "to the point" WRT its output (sorry, I don't know all the fancy PS cmdlets, so it might be a tad bulky!):
$string = "(09:40:23)(00:00:03)" 

#$string = "(00:00:03)" # Using this returns one match, so the regular expression is not totally wasted

$matches = [System.Text.RegularExpressions.Regex]::Matches($string, "[0-3][0-9]:[0-5][0-9]:[0-5][0-9]")

$list = @()

foreach ($match in $matches)
{
    $list += $match.Value
}

$list | ft -autosize

Open in new window

0
 
LVL 1

Author Comment

by:jmateknik
ID: 34919974
With your help I came on the right track. The .NET variant (as opposed to the  -match operator in combination with $matches) is a more wealthy object to deal with.

I ended up with the following code, that is a slight modification of your code:
 
[string] $string = "(09:40:23)(00:00:03)"
[Regex]$TimeRegex = "[0-3][0-9]:[0-5][0-9]:[0-5][0-9]"

[array]$matches	= $TimeRegex.matches($string) | ForEach-Object { $_.value }
[int]$Values = $Matches.length

if ($Values -eq 2) { $Matches[1] }
else { "Plan B" }

Open in new window

Thank you for your helpfullness along the way kaufmed - you are soon to be even more wealthy Genius :)
Thank you shinuq and sjklein42 for showing your face...
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34921222
Glad you got it working   = )
0
 
LVL 1

Author Comment

by:jmateknik
ID: 34921278
This link helped me btw:
Powershell Tutorial chapter-13-text-and-regular-expressions

It states:
It's true here, too, that -match finds only the first match. If your raw text has several occurrences of the keyword, use a RegEx object again:
0

Featured Post

Need protection from advanced malware attacks?

Look no further than WatchGuard's Total Security Suite, providing defense in depth against today's most headlining attacks like Petya 2.0 and WannaCry. Keep your organization out of the news with protection from known and unknown threats.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Windows 10 came with  a lot of built in applications, Some organisations leave them there, some will control them using GPO's. This Article is useful for those who do not want to have any applications in their image (example:me).
A quick Powershell script I wrote to find old program installations and check versions of a specific file across the network.
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question