Gordon
Gordon

Reputation: 6863

Get number before a specified string

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

Answers (7)

Andrei Odegov
Andrei Odegov

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

TheMadTechnician
TheMadTechnician

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

TessellatingHeckler
TessellatingHeckler

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

user6811411
user6811411

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

Joshua J Wilborn
Joshua J Wilborn

Reputation: 526

Updated Regex:
/(\d+) \/ (\d+) (\d+)=\D+(\d+)=peak/gi

Upvotes: 0

Esperento57
Esperento57

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

user6811411
user6811411

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

Related Questions