0

How could I check if there is the "data" value between my two other "values" knowing that the number of lines spacing them is not regular and that the last "data" has no "value" after it?

values
xxx
xxx
data
xxx
values
xxx
xxx
values
xxx
data
values
xxx
data
xxx

All I have is:

    if (xxx) {
        xxx | Add-Content -Path $DATA
    } else {
        Add-Content -Path $DATA -Value 'N/A'
    }

And in the end the result I would like is :

data
N/A
data
data

2 Answers 2

1

You can use a Select-String approach:

# $s contains a single string of your data
($s | Select-String -Pattern '(?s)(?<=values).*?(?=values|$)' -AllMatches).Matches.Value |
    Foreach-Object {
        ('N/A',$matches.0)[$_ -match 'data']
    }

Explanation:

-Pattern without -SimpleMatch uses regex. (?s) is a single-line modifier so that . matches newline characters. (?<=values) is a positive lookbehind for the string values. (?=values|$) is a positive lookahead for the string values or (|) the end of string ($). Using lookaheads and lookbehinds prevents values from being matched so that each one can be used in the next set of matches. Otherwise, once values is matched, it can't be used again in another match condition. .*? lazily matches all characters.

Inside the Foreach-Object, the current match object $_ is checked for data. If data is found, automatic variable $matches gets updated with its value. Since $matches is a hash table, you need to access capture group 0 (0 is the key name) for the value.

It is imperative that $s be a single string here. If you are reading it from a text file, use $s = Get-Content file.txt -Raw.


You could make this a bit more dynamic using variables:

$Start = 'values'
$End = 'values'
$data = 'data'
($s | Select-String -Pattern "(?s)(?<=$Start).*?(?=$End|$)" -AllMatches).Matches.Value |
    Foreach-Object {
        ('N/A',$matches.0)[$_ -match 'data']
    }
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you that helps me a lot, but I still have two problems. The first one is that I do other match before and that obviously the last match is resumed and I find it in my list so I don't know if there is a way to reset it. The second one is that when I try to search several "data" in this way: Foreach-Object { ('N/A',$matches.0)[$_ -match 'Data1'] ('N/A',$matches.0)[$_ -match 'Data2'] ('N/A',$matches.0)[$_ -match 'Data3'] } The "N/A's" always put themselves first and therefore the data do not come out in the right order.
For the second problem just use ('N/A',$matches.0)[$_ -match 'Data1|Data2|Data3']
0

You'll want to read the lines one by one, and keep track of 1) when you see a values line and 2) when you see a data line.

I prefer switch statements for this kind of top-down parsing:

# In real life you would probably read from a file on disk, ie.
# $data = Get-Content some\file.txt
$data = -split 'values xxx xxx data xxx values xxx xxx values xxx data values xxx data xxx'

# Use this to keep track of whether the first "values" line has been observed 
$inValues = $false

# Use this to keep track of whether a "data" line has been observed since last "values" line
$hasData = $false

switch($data)
{
  'values' {
    # don't output anything the first time we see `values`
    if($inValues){
      if($hasData){
        'data'
      } else {
        'N/A'
      }
    }
    
    $inValues = $true
    # reset our 'data' monitor
    $hasData = $false
  }

  'data' {
    # we got one!
    $hasData = $true
  }
}

if($inValues){
  # remember to output for the last `values` block
  if($hasData){
    'data'
  } else {
    'N/A'
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.