Joe*_*son 4 string powershell match select-string
我需要在多行字符串变量的匹配之前返回一行.
当输入使用字符串变量时,Select-String似乎认为整个字符串已匹配.因此,Context属性在字符串的两端"外部"并且为null.
考虑以下示例:
$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
}
Run Code Online (Sandbox Code Playgroud)
我在这里误解了什么吗?
匹配"line3"时返回"line2"的最佳方法是什么?
谢谢!
编辑:我忽略的附加要求:需要在所有匹配的行上方提供一行不确定长度的行.EG在下面搜索"line3"时我需要返回"line2"和"line5".
line1
line2
line3
line4
line5
line3
line6
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
这会产生:
line before: line2
matched part: line3
line before: line5
matched part: line3
Run Code Online (Sandbox Code Playgroud)
$teststring -split '\r?\n' 将多行字符串拆分为一行数组:
\r?\n处理任何一种风格.请注意,使用管道提供Select-String输入至关重要; 如果您使用-InputObject,则阵列将被强制转换回单个字符串.
Select-String很方便,但很慢.
特别是对于已经在内存中的单个字符串,使用.NET Framework [Regex]::Matches()方法的解决方案将表现得更好,尽管它更复杂.
请注意,PowerShell自己的-match和-replace运算符构建在同一个.NET类上,但不公开其所有功能; -match- 在自动$Matches变量中报告捕获组- 这里不是一个选项,因为它只返回1个匹配.
以下基本上与mjolinor的答案答案相同,但纠正了几个问题[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
}
Run Code Online (Sandbox Code Playgroud)
Regex (?:^|(.*)\n).*(line3)使用2个捕获组((...))来捕获要匹配的行(匹配部分)和之前的行((?:...)是优先级所需的辅助非捕获组):
(?:^|(.*)\n)匹配string(^)或(|)的最开头- 可能是空的 - 非换行符(.*)后跟换行符(\n); 这确保了当没有前一行时(即,要匹配的行是第一行),也可以找到要匹配的行.(line3)是定义要匹配的行的组; 它前面是.*匹配问题中的行为,其中line3找到模式,即使它只是一行的一部分.
(?:^|(.*)\n)(line3)(?:\n|$)[Regex]::Matches()查找所有匹配项并将它们作为System.Text.RegularExpressions.Match对象集合返回,ForEach-Object然后cmdlet调用可以对其进行操作以提取capture-group matches($_.Groups[<n>].Value).
[1]在撰写本文时:
- 没有必要匹配两次 - 封闭if ($teststring -match $pattern) { ... }是不必要的.
-内嵌选项(?m)是不需要的,因为.它不匹配换行符默认.
- (.+?)仅捕获非空行(并且?,不需要非贪婪量词).
- 如果感兴趣的行是第一行 - 即,如果之前没有行,则不会匹配.
| 归档时间: |
|
| 查看次数: |
5446 次 |
| 最近记录: |