如何在Powershell中提取正则表达式的反向引用/匹配值

24

我有一个包含数据行的文本文件。我可以使用以下powershell脚本来提取我感兴趣的行:

select-string -path *.txt -pattern "subject=([A-Z\.]+),"

一些示例数据可能是:

blah blah subject=THIS.IS.TEST.DATA, blah blah blah

我想要的是仅提取主题实际的内容(即"THIS.IS.TEST.DATA"字符串)。我尝试了这个:

select-string -path *.txt -pattern "subject=([A-Z\.]+)," | %{ $_.Matches[0] }

但是,“Matches”属性始终为空。我做错了什么?


这对我有效。还有其他问题,比如使用PowerShell 1或一些奇怪的编码,例如UTF8无BOM或UTF16LE无BOM。 - js2010
8个回答

17

我不知道为什么你的版本不能运行。它应该是可以的。这里有一个更丑陋的版本可以工作。

$p = "subject=([A-Z\.]+),"
select-string -path *.txt -pattern $p | % {$_ -match $p > $null; $matches[1]}

说明:

-match是一个正则表达式匹配运算符:

>"foobar" -match "oo.ar"
True
< p> > $null 只是阻止True被写入输出。(尝试将其删除.)有一个做同样事情的cmdlet,但我现在不记得它的名字了。

$matches是一个魔术变量,它保存了最后一个-match操作的结果。


谢谢,这个可以用,但是你能解释一下你在做什么吗?特别是 "$_ -match $p > $null" 这一部分。 - d4nt
1
dangph 考虑使用的 cmdlet 是 "Out-Null"。但你也可以将整行转换为 [void]:[void]($_ -match $p)。 - JasonMArcher

8
在PowerShell V2 CTP3中,实现了Matches属性。所以以下代码可以正常工作:
select-string -path *.txt -pattern "subject=([A-Z\.]+)," | %{ $_.Matches[0].Groups[1].Value }

4
另外一个选项。
gci *.txt | foreach { [regex]::match($_,'(?<=subject=)([^,]+)').value }

4

在IT技术中,有一个比select-string更简单且效果更好的替代方案。

在powershell中,

  1. $sample="blah blah subject=THIS.IS.TEST.DATA, blah blah blah"
  2. $sample -match "subject=([A-Z\.]+),"
  3. $matches[1]将包含你正在查找的子字符串。

这适用于Windows 10.0.16299版本。


2
迄今为止最干净和最简单的解决方案。应该是第一名。 - Mark Worrall

2

从其他答案中我学到了很多,最终使用以下代码实现了我的目标:

gci *.txt | gc | %{ [regex]::matches($_, "subject=([A-Z\.]+),") } | %{ $_.Groups[1].Value }

这种方法很不错,因为每行只运行一次正则表达式,并且在命令提示符中输入时,没有多行代码的情况,感觉很好。

很高兴您找到了解决方案。我刚在v2中检查了Matches属性,它可以从Select-String中工作。所以在将来,这对您来说将会更加轻松。 :) - JasonMArcher

1
你正在输入的代码存在问题,即 select-string 没有传递实际的正则表达式对象。相反,它传递了一个名为 MatchInfo 的不同类,该类没有实际的正则表达式匹配信息。
如果你只想运行一次正则表达式,你将不得不编写自己的函数,这并不太困难。
function Select-Match() {
  param ($pattern = $(throw "Need a pattern"), 
         $filePath = $(throw "Need a file path") )
  foreach ( $cur in (gc $filePath)) { 
    if ( $cur -match $pattern ) { 
      write-output $matches[0];
    }
  }
}

gci *.txt | %{ Select-Match "subject=([A-Z\.]+)," $_.FullName }

但是为什么MatchInfo.Matches属性不起作用呢? - dan-gph
@dangph,我相信这是文档中的一个错误。您可以通过运行“gci a *.txt | gm”来验证。生成的类型没有Matches属性。 - JaredPar
JaredPar,那对我没用,但我相信你是对的。试试这个:“gm -inputobject (new-object Microsoft.PowerShell.Commands.MatchInfo)”。 - dan-gph
我猜他们只是还没有实现Matches属性。毕竟,我期望一个名为“MatchInfo”的类实际上应该包含有关匹配的信息:)) - dan-gph
1
我刚在CTP3中检查了一下,Matches属性已经实现了v2版本。 - JasonMArcher
显示剩余3条评论

1
Select-String命令似乎返回的是一个MatchInfo变量而不是一个"string"变量。我在论坛和官方网站上花了几个小时都没有找到答案。我还在收集信息。解决这个问题的方法是明确声明一个字符串变量来保存从Select-String返回的结果,就像你的例子一样:
[string] $foo = select-string -path *.txt -pattern "subject=([A-Z.]+),"
现在$foo变量是一个字符串而不是MatchInfo对象。希望这可以帮助你。
PS5 PowerShell版本5字符串字符串操作

0

另一种变体,匹配字符串中的7个数字

echo "123456789 hello test" | % {$_ -match "\d{7}" > $null; $matches[0]}

返回:1234567


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接