如何获得满足特定条件的$ Matches索引的索引?

时间:2018-11-01 12:41:37

标签: regex powershell

我将读取一个文本文件并将其过滤到我只需要的行中,然后使用正则表达式提取内容。之后,我将找到小于特定值的值并获取其索引。使用该索引,我将重复上述步骤并提取另一个匹配项。拿到那组比赛后,我停留在。我该如何进行?下面的示例只是文本文件的一行,以方便说明。

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

$Matches[2]类似于:

0
66785
3434
125
0
24324
0
55

我正在尝试获取小于30的值的索引,以便可以从同一文件的另一个正则表达式匹配中提取所需的下一个信息。

$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?
    }
}

提前谢谢!感谢任何帮助!

输入文件内容的

Some 。实际文件将具有以下重复块:

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

2 个答案:

答案 0 :(得分:1)

我想您要输出所有作业的文件名,其中少于30帧的文件名编码?这是您要尝试的吗?

$content = Get-Content -Path "C:\log.txt"
$index = 0
$indexes = ($content | Select-String -Pattern 'encoded' | foreach {
    if($_ -match "(.*) ([0-9]*) (.*),(.*)") {
        # "remember" the indexes of the matches
        if ([int]$Matches[2] -lt 30) {
            $index
        }
        $index++
    }
})
$index = 0
$content | Select-String -Pattern 'Input' | foreach {
    if($_ -match "(.*) '(.*)':") {
        # output if index matches
        if ($indexes -contains $index) {
            $Matches[2]
        }
        $index++
    }
}

(更短的)替代解决方案:

get-content "C:\log.txt" | foreach {
    if ($_ -like "Input*" -and $_ -match "(.*) '(.*)':") {
        $file = $Matches[2]
    }
    if ($_ -like "encoded*" -and $_ -match "(.*) ([0-9]*) (.*),(.*)" -and [int]$Matches[2] -lt 30) {
        $file
    }
}

请尝试将其与您的实际输入文件配合使用。

此外,我认为您的正则表达式模式可以改善,但目前看来,它们可以完成工作。

答案 1 :(得分:1)

这个问题有一个误解。 $matches[2]将不是您需要索引的值的数组。它将代表foreach-object块的每个交互的标量值。这些结果都分别通过管道 发送。

尽管如此,我仍然想回答这个问题。给定一个值数组,请确定其中哪些值低于阈值,然后返回其在数组中位置的索引。

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

这类似于您在上面显示的代码。它将值保存到名为$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"
    }
}

然后,我们使用计数器逐一循环数组元素。检查每个值并报告我们当前所在的索引。

鉴于这种情况,我将完全走一条不同的路线


我想朝着稍稍的方向发展。理解每个文件都有多个块,就像您在问题中显示的那样,它将对应于您正在处理的多个文件,并且您只对编码帧少于30个的文件感兴趣。

注意:此解决方案在很大程度上取决于真实数据的外观。我只能根据问题所在继续进行。如果实际数据偏离过多,则不能保证该解决方案能够正常工作或给出预期结果。

使用[regex]可以将文件拆分为多个块。 Using names capture groups我们可以仅从所需的每个“块”中提取值。非贪婪的捕获将确保我们在任何给定的块之外都不匹配。然后,我们将创建自定义对象,可以像常规PowerShell对象一样对其进行过滤。

如果名为C:\ log.txt的文件如下所示:

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

我们可以运行此代码:

$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 
    }

}

独自返回

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

因此让我们过滤该输出。将以下内容添加到最后一行,即,在Foreach块的右括号后:| Where-Object{$_.EncodedFrames -lt 30},您将得到所需的内容。然后,您可以添加| Select-Object -expand Filename来获取这些文件名。

现在在一起

$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