代码之家  ›  专栏  ›  技术社区  ›  Josh Gust

为什么powershell-replace操作符不能正确地包含捕获组中捕获的所有字符?

  •  1
  • Josh Gust  · 技术社区  · 6 年前

    在再次回顾这个问题之后,我添加了第二个例子,我希望它能突出我的困惑被放大的地方,也就是说,有一个捕获组通过它的索引(1)访问,我期望从 $filecontent


    This question

    如果您需要在替换表达式中引用其他变量(如您所愿),可以使用双引号字符串并用反勾号转义捕获美元

    $VersionReplacementRegex = "(\d+\.)\d+" #capture first digit + dot b/c I want to keep it
    $BuildVersionValidationRegex = "\d+\.\d+\.\d+"
        
    $VersionData = [regex]::matches("some-18.11.8",$BuildVersionValidationRegex)
    $NewVersion = $VersionData[0] #matches 18.11.8
    
    $filecontent = "stuff 1.0.0.0 other stuff" #Get-Content($file)
    

    替换中的文本 $文件内容

    $filecontent -replace $VersionReplacementRegex, "`$1$NewVersion" | Write-Host
    

    退货: 118.11.8 1.18.11.8

    $1 $NewVersion 给出了一个不同但同样无益的结果。。

    $filecontent -replace $VersionReplacementRegex, "`$1 $NewVersion" | Write-Host
    

    1. 18.11.8

    在本例中,结果有些相似,但似乎capture组得到的值都是错误的。

    $NewVersion = 18.11.8
    $filecontent = "stuff 5.0.0.0 other stuff"
    $filecontent -replace "(\d+\.)\d+", "`$1$NewVersion" | Write-Host
    
    # returns: 118.11.8
    # expected: 5.18.11.8
    

    在替换字符串中添加空格将返回: 5. 18.11.8

    1 回复  |  直到 4 年前
        1
  •  1
  •   mklement0    6 年前

    从过去的经验来看, PetSerAl 他在对这个问题的评论中提供了关键的指针,他不会回来发表答案。

    热释光;博士

    -replace 使用引用捕获组的替换操作数 动力壳 变量,使用如下语法 "`${<ndx>}${<PsVar>}" <ndx> 是捕获组的索引,以及 <PsVar> 是PowerShell变量的名称;注意 ` 在第一个之前 $ :

    PS> $var = '2'; 'foo' -replace '(f)', "[`${1}$var]"
    [f2]oo # OK, -replace saw '${1}2'
    

    {...} 为了消除捕获组索引的歧义,替换发生故障,因为插入的字符串值随后有效地引用了不同的索引:
    -替换 然后看到 [$12] ,这是由于引用了不存在的具有索引的捕获组 12 ,保持原样:

    PS> $var = '2'; 'foo' -replace '(f)', "[`$1$var]"
    [$12]oo # !! -replace saw '$12', i.e., a nonexistent group with index 12
    

    串展开 (插值)用
    -替换
    ,因为它是 容易混淆

    • 双引号 "..." )字符串,这是PowerShell的泛型 串展开 $ 字符 第一 前缀引用(PowerShell) 还有,里面 $(...) .

    • 结果 扩张的一部分是 -替换 接线员,哪里 $ -前缀标记指 正则表达式匹配操作的结果 ,如中所述 this answer .

    • 请注意,这些层 解释是完全不相关的,事实上两者都使用sigil 是偶然的。

    因此:

    • 如果替换操作数 需要字符串扩展 变量 使用 字符串( '...' ,这样PowerShell的字符串扩展就不会起作用:

       PS> 'foo' -replace '(f)', '[$1]'
       [f]oo  # OK - if you had used "[$1]" instead, the output would be '[]oo',
              # because $1 is then interpreted as a *PowerShell variable*.
      
    • 如果你 :

      • $ 应该传递给 -替换 具有 `

        • (backtick)是PowerShell的一般转义字符,在 字符串它用于指示要使用的下一个字符 ; 放在 $ ,它抑制该标记的字符串插值;例如。, "I'm `$HOME" I'm $HOME ,即变量引用为
      • 消除引用的歧义 $1 把它们围起来 {...} -例如。, ${1}

        • 消除歧义 动力壳 变量名;例如 "$HOME1" 必须是 "${HOME}1" $HOME
        • 而且,这不仅仅是关于捕获组 ; 模棱两可的情况也会出现 命名 在里面 -基替换操作数,始终使用 {...} 围绕捕获组索引/名称(和PS变量)是一个好习惯。
      • 如果有疑问,请自行输出替换操作数以检查 -替换

        • 在上面的例子中,输出 "[`$1$var]" 如果采用字符串插值步骤,问题就更明显了:

    为了说明后一点:

    PS> $var = '2'; 'foo' -replace '(f)', "[`$1$var]"
    [$12]oo  # !! $1 wasn't recognizes as the 1st capture group.
    

    问题是 -替换 ,串展开后,锯 作为替换操作数,并且由于没有带索引的捕获组 ,它保持原样。

    将捕获组编号括在 解决问题:

    PS> $var = '2'; 'foo' -replace '(f)', "[`${1}$var]"
    [f2]oo  # OK