Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the index of $Matches index that satisfy certain criteria?

I will be reading a text files and filtered it to the lines that I only need, then using regex to extract the content. After that, I would be finding the value that is smaller than certain value and get its index. With that index I'll be repeat be repeating the steps mentioned and extract another matches. I stuck at after getting the group of the matches. How do I proceed? Example below is only a line of the text file for easy of explanation.

$content=Get-Content -Path "C:\log.txt"
$content | Select-String -Pattern 'encoded' | ForEach-Object {
     if($_ -match "(.*) ([0-9]*) (.*),(.*)"){
         $Matches[2]         
     }
}

$Matches[2] would be something like:

0
66785
3434
125
0
24324
0
55

I'm trying to get the index of the value that's smaller than 30, so that I could extract the next information I want from another regex matching of the same file.

$content=Get-Content -Path "C:\log.txt"
$content | Select-String -Pattern 'Input' | ForEach-Object {
    if($_ -match "(.*) '(.*)':"){
        $Matches[2]
        # How do I extract the content of the $Matches[2] here from the previously obtained indexes?
    }
}

Thanks in advance! Appreciate any help!

Some of the input file content. The real file would have repeated blocks of this:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\myvideo.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf54.63.104
Output #0, mp4, to 'C:\output\myvideo.mp4':
  Metadata:
    encoder         : Lavf58.15.100
    Stream #0:0(und): Video: hevc (Main 10) (hev1 / 0x31766568), yuv420p10le(progressive), 864x480, q=2-31, 12800 tbn (default)
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp (default)
    Metadata:

encoded 2058 frames, 1376.59 fps, 373.36 kbps, 3.66 MB
like image 568
Gregor Isack Avatar asked Dec 06 '25 11:12

Gregor Isack


1 Answers

There is a misconception in the question. $matches[2] would not be an array of values you need to index. It would represent a scalar value for each interation of the foreach-object block. Those results are all sent down the pipeline individually.

I would still like to answer the question as stated though. Given an array of values, determine which of those is below a threshold and return the index of its position in the array.

$results = $content | Select-String -Pattern 'encoded' | 
    Where-object{$_ -match "(.*) ([0-9]*) (.*),(.*)"} | 
    ForEach-Object{$Matches[2]}

This is similar to the code you show above. It saves the values into an array called $results.

$threshold = 30
for($index=0; $index -lt $results.count; $index++){
    if([int]$results[$index] -lt $threshold){
        Write-Host "The value at index $index is $($results[$index]) which is below $threshold"
    }
}

Then we cycle the array elements, one by one, using a counter. Check every value and report the index we were currently at.

Given the scenario, I would go a different route altogether


I would like to take this in a slightly different direction. Understanding that each file with have multiple blocks like you show in the question that will correspond to multiple files you are processing and you are only interested in files where there are less than 30 encoded frames.

Note: This solution is heavily dependent on how the real data looks. I can only go on based what is in the question. If the real data deviates too much from that the solution is not guaranteed to work or give expected results.

Using [regex] lets split the file into its chunks. Using names capture groups we can pull just the values from each "block" that you want. Non-greedy captures will ensure we don't match outside of any given block. Then we make custom objects that we can filter just like you would normal PowerShell objects.

If the file called C:\log.txt looked like this:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\myvideo.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf54.63.104
Output #0, mp4, to 'C:\output\myvideo.mp4':
  Metadata:
    encoder         : Lavf58.15.100
    Stream #0:0(und): Video: hevc (Main 10) (hev1 / 0x31766568), yuv420p10le(progressive), 864x480, q=2-31, 12800 tbn (default)
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp (default)
    Metadata:

encoded 2058 frames, 1376.59 fps, 373.36 kbps, 3.66 MB

Input #1, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\myvideo2.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf54.63.104
Output #0, mp4, to 'C:\output\myvideo2.mp4':
  Metadata:
    encoder         : Lavf58.15.100
    Stream #0:0(und): Video: hevc (Main 10) (hev1 / 0x31766568), yuv420p10le(progressive), 864x480, q=2-31, 12800 tbn (default)
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp (default)
    Metadata:

encoded 0 frames, 1376.59 fps, 373.36 kbps, 3.66 MB

We could run this:

$content = Get-Content -Path "C:\log.txt" -Raw

[regex]::Matches($content,"(?sm)Input #(?<number>\d+).*?from '(?<filename>.*?)'.*?encoded (?<frames>\d+)") | ForEach-Object{
    [pscustomobject]@{
        Index = $_.Groups["number"].Value 
        Filename = $_.Groups["filename"].Value 
        EncodedFrames = [int]$_.Groups["frames"].Value 
    }

}

On its own would return

Index Filename        EncodedFrames
----- --------        -------------
0     C:\myvideo.mp4  2058         
1     C:\myvideo2.mp4 0          

So lets filter that output. Add onto the last line the following i.e. after the Foreach block ending parentheses: | Where-Object{$_.EncodedFrames -lt 30} and you would get just the ones you want. Then you could add | Select-Object -expand Filename to just get those file names.

All together now

$content = Get-Content -Path "C:\log.txt" -Raw

[regex]::Matches($content,"(?sm)Input #(?<number>\d+).*?from '(?<filename>.*?)'.*?encoded (?<frames>\d+)") | ForEach-Object{
    [pscustomobject]@{
        Index = $_.Groups["number"].Value 
        Filename = $_.Groups["filename"].Value 
        EncodedFrames = [int]$_.Groups["frames"].Value 
    }

} | Where-Object{$_.EncodedFrames -lt 30} | Select-Object -expand Filename
like image 59
Matt Avatar answered Dec 08 '25 01:12

Matt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!