选择字符串:仅当字符串前面没有特定字符时才匹配它

时间:2019-02-28 18:24:44

标签: regex powershell regex-negation regex-lookarounds select-string

我有一个包含两个字符串之一的文件列表:

stuff”或“ ;stuff

我正在尝试编写PowerShell脚本,该脚本将仅返回包含“ stuff”的文件。下面的脚本当前返回 all 个文件,因为显然“ stuff”是“ ;stuff”的子字符串

对于我来说,我无法弄清楚如何仅匹配包含“ stuff”的文件,而没有前面的;

Get-Content "C:\temp\list\list.txt" |
  Where-Object { Select-String -Quiet -Pattern "stuff" -SimpleMatch $_ }

注意:C:\temp\list\list.txt包含一个文件路径列表,每个文件路径都传递给Select-String

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

您无法通过 literal 子字符串搜索(-SimpleMatch)执行所需的匹配。

相反,使用带有负向后看断言 (?<!..))的 regex 来排除{{1} }子字符串后跟一个stuff字符:;

应用于您的命令:

(?<!;)stuff

正则表达式陷阱:

  • 使用{strong>负(Get-Content "C:\temp\list\list.txt" | Where-Object { Select-String -Quiet -Pattern '(?<!;)stuff' -LiteralPath $_ } )字符集([^;]stuff )来代替^(请参阅{{3} });但是,如果[...]出现在行的 处,这将不能正常工作,因为一个字符集(无论是否取反)都只匹配一个实际的字符,而不是行首的位置

  • 然后很容易将stuff应用于否定字符集(对于可选匹配-0或1次出现):?。但是,这将再次匹配包含[^;]?stuff的字符串,因为;stuff技术上之前是取反字符集的“ 0重复出现”;因此,stuff产生';stuff' -match '[^;]?stuff'

在这种情况下,只有后置断言可以正常工作-参见this answer

答案 1 :(得分:1)

为补充@ mklement0的答案,我建议一种替代方法,使您的代码更易于阅读和理解:

MANIFEST.MF

这会将您的字符串变成对象(#requires -Version 4 @(Get-Content -Path 'C:\Temp\list\list.txt'). ForEach([IO.FileInfo]). Where({ $PSItem | Select-String -Pattern '(?<!;)stuff' -Quiet }) ),并利用数组函数ForEachWhere来简化/简洁。此外,这使您可以将System.IO.FilePath参数将接受的路径作为对象传递到-Path中,以使其更易于理解(我发现很长的参数集列表很困难阅读)。

答案 2 :(得分:-1)

发布的示例代码实际上不会运行,因为它将每行视为-Path值。

您需要获取的内容,选择要查找的字符串,然后使用Where-Object过滤结果

Get-Content "C:\temp\list\list.txt" | Select-String -Pattern "stuff" | Where-Object {$_ -notmatch ";stuff"}

如果需要,您可以创建更复杂的正则表达式,但取决于文件中结果数据的样子