Reputation: 6863
Given the string
RAM Statistics: 5954 / 8174 743=InUse 746=Peak
I need a RegEx (or three) to extract the 743
, the 746
, and ideally the 5954 / 8174
so each can be assigned to a specific variable.
I THINK this is what LookBehind is used for, but I am having a hell of a time actually getting a RegEx to "Get the numbers between a Space and =Peak", for example.
I have tried
$string = 'RAM Statistics: 5954 / 8174 743=InUse 746=Peak'
$regexPeak = '(?<= )(.#)(?=\=Peak)'
$string -match $regexPeak > $null
$peak = $matches[0]
Write-Host "$peak"
But that's returning nothing.
UPDATE: Per Joshua I have tried
$string = 'RAM Statistics: 5954 / 8174 743=InUse 746=Peak'
$regexPeak = '(\d+) / (\d+) (\d+)=\D+(\d+)=peak/gi'
$string -match $regexPeak
$peak = $matches[0]
Write-Host "$peak!"
And both $matches[0] and [1] return everything before the =Peak. So
Statistics: 5954 / 8174 743=InUse 746!
Upvotes: 1
Views: 571
Reputation: 3429
[regex]::Matches('RAM Statistics: 5954 / 8174 743=InUse 746=Peak','\D+(\d+)')|%{$_.groups[1].value}
It gives the next result::
5954
8174
743
746
Upvotes: 0
Reputation: 36297
Ok, slightly different approach here, using a RegEx object instead of the -match
operator. Since you mentioned inconsistency I have run this twice, once with added garbage text and extra whitespace, and once with only some of the items present.
$MyRegEx = ([regex]'\b(?<peak>\d+)(?=\=Peak)|(?<ratio>\d+\s*\/\s*\d+)|\b(?<inuse>\d+)(?=\=InUse)')
$String='RAM Statistics: 5954 / 8174 1=somegarbage 743=InUse 746=Peak'
$Results=$MyRegex.matches($String)
Switch($Results){
{$_.groups['ratio'].success}{"Ratio = " + $_.Groups['ratio'].value}
{$_.groups['inuse'].success}{"InUse = " + $_.Groups['inuse'].value}
{$_.groups['peak'].success}{"Peak = " + $_.Groups['peak'].value}
}
$String2 = 'RAM Statistics: 5954 / 8174 746=Peak'
$Results=$MyRegex.matches($String2)
Switch($Results){
{$_.groups['ratio'].success}{"Ratio = " + $_.Groups['ratio'].value}
{$_.groups['inuse'].success}{"InUse = " + $_.Groups['inuse'].value}
{$_.groups['peak'].success}{"Peak = " + $_.Groups['peak'].value}
}
That will get you the results of:
Ratio = 5954 / 8174
InUse = 743
Peak = 746
and for the second string:
Ratio = 5954 / 8174
Peak = 746
This is accomplished by using named capture groups, and then evaluating the results looking if that capture group succeeded in the specific grouping. I accomplish that with a Switch
.
Upvotes: 0
Reputation: 28983
Just to pull apart your trial code:
$string = 'RAM Statistics: 5954 / 8174 743=InUse 746=Peak'
$regexPeak = '(?<= )(.#)(?=\=Peak)'
Your regex has a lookbehind for a space, which is OK. Then it has a middle bit with a grouping of (.#)
and that almost certainly is not doing what you intend - a dot matches any single character, and a hash matches a hash. So it would match things like 4#
, z#
, ##
and not 746
. Then you have a positive lookahead, which looks OK. But the combined effect is to lock the inner bit down to two characters and look for space, two characters (where the second is a hash), equals peak
.
Probably you want \d
to mean a digit, and +
to mean "match one or more times", so \d+
The second thing you're doing is mixing up lookarounds and grouping. One use of regex involves matching a string like 'number is 4'
with a pattern like 'number is (\d)'
. The whole pattern matches and appears in the output, and then you query the capture groups to pick out the 4
out of the whole match. $matches[0]
is number is 4
and $matches[1]
is 4
.
Another use of regex involves matching the number with a lookbehind like (?<=number is )\d
because the lookbehind matches but it doesn't appear in the output. So the output of $matches[0]
is just the 4
and you don't need any groups. So you're using lookarounds to match without having the text in the output, and trying to group the number as well, which works but it's overkill / unnecessary mixed use of two different approaches.
That means your regex is very close to working:
$regexPeak = '(?<= )(.#)(?=\=Peak)' # change to
$regexPeak = '(?<= )\d+(?=\=Peak)' # to indicate "one or more digits"
and:
PS C:\> $string = 'RAM Statistics: 5954 / 8174 743=InUse 746=Peak'
PS C:\> $regexPeak = '(?<= )\d+(?=\=Peak)'
PS C:\> $string -match $regexPeak > $null
PS C:\> $peak = $matches[0]
PS C:\> $peak
746
Upvotes: 1
Reputation:
Another answer with a more complex RegEx with named groups which works on regex101.com but fails with the script. I guess due to differences in the RegEx implementation.
$string = @'
RAM Statistics: 1954 / 8174 743=InUse 746=Peak
RAM Statistics: 2954 / 8174 746=Peak
RAM Statistics: 3954 / 8174 743=InUse
RAM Statistics: 4954 / 8174
'@
$Pattern = '(?sm)^RAM Statistics: *(?<Ram>\d+) *\/ *(?<Ratio>\d+)( *(?<InUse>\d+)=InUse)?( *(?<Peak>\d+)=Peak)?'
$string.split('`n') |ForEach{
$_ -match $Pattern|out-null
"RAM {0}/{1} {2} InUse {3} Peak" -f $Matches.Ram,$Matches.Ratio,$Matches.InUse,$Matches.Peak
}
RAM 1954/8174 InUse Peak
RAM 2954/8174 InUse 746 Peak
RAM 4954/8174 InUse Peak
Upvotes: 0
Reputation: 17462
Other method, without regex
$template=@"
{Data:RAM Statistics:{RamStat: 123456 / 123} {InUseValue:743}=InUse {PeakValue:746}=Peak}
"@
$string = 'RAM Statistics: 5954 / 8174 743=InUse 746=Peak'
$result=$string | ConvertFrom-String -TemplateContent $Template
write-host "RamStat : " $result.Data.RamStat
write-host "PeakValue : " $result.Data.PeakValue
write-host "InUseValue : " $result.Data.InUseValue
Upvotes: 0
Reputation:
$Pattern = '(\d+) *\/ *(\d+) +(\d+)=[^0-9]*(\d+)'
$string = 'RAM Statistics: 5954 / 8174 743=InUse 746=Peak'
if ($string -match $Pattern){$Matches[0..4]}
5954 / 8174 743=InUse 746
5954
8174
743
746
Upvotes: 2