【问题标题】:How do you extract the value of a regex backreference/match in Powershell如何在 Powershell 中提取正则表达式反向引用/匹配的值
【发布时间】:2020-06-09 23:38:57
【问题描述】:

我有一个包含数据行的文本文件。我可以使用以下 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] }

但“匹配”属性始终为空。我做错了什么?

【问题讨论】:

  • 这对我有用。正在发生其他事情,例如使用 powershell 1 或一些奇怪的编码,例如 utf8 no bom 或 utf16le no bom。

标签: regex powershell


【解决方案1】:

我不知道为什么您的版本不起作用。它应该工作。这是一个更丑的版本。

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

解释:

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

>"foobar" -match "oo.ar"
True

> $null 只是禁止将 True 写入输出。 (尝试删除它。)有一个 cmdlet 做同样的事情,我现在不记得它的名字了。

$matches 是一个神奇的变量,它保存最后一次-match 操作的结果。

【讨论】:

  • 谢谢,这行得通,但你能解释一下你在做什么吗?特别是“$_ -match $p > $null”位。
  • dangph 考虑的 cmdlet 是“Out-Null”。但你也可以将整行转换为 [void]: [void]($_ -match $p)
【解决方案2】:

在 PowerShell V2 CTP3 中,实现了 Matches 属性。所以以下将起作用:

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

【讨论】:

    【解决方案3】:

    另一种选择

    gci *.txt | foreach { [regex]::match($_,'(?<=subject=)([^,]+)').value }
    

    【讨论】:

      【解决方案4】:

      选择字符串有一个更简单的替代方法,效果会更好。

      在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 版本

      【讨论】:

      • 迄今为止最干净、最简单的解决方案。应该是#1。
      【解决方案5】:

      从所有其他答案中学到了很多东西,我能够使用以下行得到我想要的:

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

      这感觉很好,因为我每行只运行一次正则表达式,而且当我在命令提示符下输入它时,没有多行代码真是太好了。

      【讨论】:

      • 很高兴您找到了解决方案。我刚刚签入 v2,并且 Matches 属性适用于 Select-String。所以在未来,这对你来说不会那么痛苦。 :)
      【解决方案6】:

      您输入的代码的问题是 select-string 没有传递实际的 Regex 对象。相反,它传递了一个名为 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 属性不起作用? msdn.microsoft.com/en-us/library/…
      • @dangph,我相信这是文档中的错误。您可以通过运行“gci a *.txt | gm”来验证这一点。结果类型没有 Matches 属性。
      • JaredPar,这对我不起作用,但我相信你是对的。试试这个:“gm -inputobject (new-object Microsoft.PowerShell.Commands.MatchInfo)”。
      • 我猜他们只是还没有实现 Matches 属性。毕竟,我希望一个名为“MatchInfo”的类实际上包含有关,呃,匹配的信息:))
      • 我刚刚签入CTP3,Matches属性是为v2实现的。
      【解决方案7】:

      Select-String 命令似乎返回 MatchInfo 变量,而不是“字符串”变量。 我花了几个小时在论坛和官方网站上找到了这个,但没有运气。 我还在收集信息。 解决此问题的一种方法是显式声明一个字符串变量以保存从 Select-String 返回的结果,从您的示例中:

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

      $foo 变量现在是一个字符串,而不是 MatchInfo 对象。

      希望这会有所帮助。

      ps5 powershell 版本 5 字符串操作

      【讨论】:

        【解决方案8】:

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

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

        返回:1234567

        【讨论】:

          猜你喜欢
          • 2012-11-18
          • 2018-11-25
          • 2020-07-02
          • 1970-01-01
          • 2013-09-18
          • 2020-12-03
          • 1970-01-01
          • 2011-01-12
          相关资源
          最近更新 更多