gpt4 book ai didi

string - PowerShell:选择匹配之前的行 -- Select-String - 使用输入字符串变量时的上下文问题

转载 作者:行者123 更新时间:2023-12-04 23:38:56 31 4
gpt4 key购买 nike

我需要在多行字符串变量的匹配之前返回一行。

当对输入 Select-String 使用字符串变量时,似乎整个字符串都已匹配。因此,上下文属性在字符串的任一端的“外部”并且为空。

考虑下面的例子:

$teststring = @"
line1
line2
line3
line4
line5
"@

Write-Host "Line Count:" ($teststring | Measure-Object -Line).Lines #verify PowerShell does regard input as a multi-line string (it does)

Select-String -Pattern "line3" -InputObject $teststring -AllMatches -Context 1,0 | % {
$_.Matches.Value #this prints the exact match
$_.Context #output shows all context properties to be empty
$_.Context.PreContext[0] #this would ideally output first line before the match
$_.Context.PreContext[0] -eq $null #but instead is null
}

我在这里误解了什么吗?

匹配“line3”时返回“line2”的最佳方法是什么?

谢谢!

编辑:
我忽略的其他要求:
需要为不确定长度的字符串提供所有匹配行上方的行。 EG 在下面搜索“line3”时,我需要返回“line2”和“line5”。
line1
line2
line3
line4
line5
line3
line6

最佳答案

Select-String 对输入数组进行操作,所以 您必须提供一个行数组,而不是单个多行字符串 -Context-AllMatches按预期工作:

$teststring = @"
line1
line2
line3
line4
line5
line3
line6
"@

$teststring -split '\r?\n' | Select-String -Pattern "line3" -AllMatches -Context 1,0 | % {
"line before: " + $_.Context.PreContext[0]
"matched part: " + $_.Matches.Value # Prints the what the pattern matched
}

这产生:
line before:  line2
matched part: line3
line before: line5
matched part: line3
  • $teststring -split '\r?\n'将多行字符串拆分为行数组:
  • 注意:您的 here-document 使用的换行序列(仅 LF 与 CRLF)取决于封闭的脚本文件;正则表达式 \r?\n处理任何一种风格。
  • 请注意,使用管道提供 Select-String 至关重要。的输入;如果您使用 -InputObject ,该数组将被强制返回单个字符串。


  • Select-String很方便,就是慢。
    特别是对于内存中已经存在的单个字符串, 使用 .NET Framework 的 [Regex]::Matches() 的解决方案方法会表现得更好 ,虽然是 更复杂的 .

    请注意,PowerShell 自己的 -match-replace运算符构建在同一个 .NET 类上,但不公开其所有功能; -match - 在自动 $Matches 中报告捕获组变量 - 在这里不是一个选项,因为它只返回 1 个匹配项。

    以下与 mjolinor's answer 中的方法基本相同答案,但纠正了几个问题[1]。
    # Note: The sample string is defined so that it contains LF-only (\n)
    # line breaks, merely to simplify the regex below for illustration.
    # If your script file use LF-only line breaks, the
    # `-replace '\r?\n', "`n" call isn't needed.
    $teststring = @"
    line1
    line2
    line3
    line4
    line5
    line3
    line6
    "@ -replace '\r?\n', "`n"

    [Regex]::Matches($teststring, '(?:^|(.*)\n).*(line3)') | ForEach-Object {
    "line before: " + $_.Groups[1].Value
    "matched part: " + $_.Groups[2].Value
    }
  • 正则表达式 (?:^|(.*)\n).*(line3)使用 2 个捕获组 ( (...) ) 来捕获要匹配的行和之前的行的(匹配部分)( (?:...) 是优先级所需的辅助非捕获组):
  • (?:^|(.*)\n)匹配字符串的最开始( ^ )或( | )任何 - 可能为空 - 非换行符序列( .* )后跟换行符( \n );这确保在没有前一行时也能找到要匹配的行(即要匹配的行是第一行)。
  • (line3)是定义要匹配的行的组;它前面是 .*匹配问题中的行为,其中模式 line3即使它只是一行的一部分,也会被发现。
  • 如果您只想匹配整行,请改用以下正则表达式:(?:^|(.*)\n)(line3)(?:\n|$)
  • [Regex]::Matches()查找所有匹配项并将它们作为 System.Text.RegularExpressions.Match 的集合返回对象,其中 ForEach-Object然后 cmdlet 调用可以操作以提取捕获组匹配项 ( $_.Groups[<n>].Value )。


  • [1] 在撰写本文时:
    - 不需要匹配两次 - 封闭的 if ($teststring -match $pattern) { ... }是不必要的。
    - 内联选项 (?m)不需要,因为 .默认情况下不匹配换行符。
    - (.+?)仅捕获非空行(不需要非贪婪量词 ? )。
    - 如果感兴趣的行是第一行 - 即,如果之前没有行,则不会匹配。

    关于string - PowerShell:选择匹配之前的行 -- Select-String - 使用输入字符串变量时的上下文问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44682017/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com