为什么powershell -replace运算符未正确包含捕获组中捕获的所有字符?

时间:2018-11-08 19:51:06

标签: powershell

This question表示在引用其他变量时,可以使用反勾来解决双引号字符串中的捕获组。

  

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

但是,我看到了一些我无法解释的有趣行为。

$VersionReplacementRegex = "(\d+\.)\d+\.\d+\.\d+"
$BuildVersionValidationRegex = "\d+\.\d+\.\d+-\w\d+"

$VersionData = [regex]::matches("some-18.11.8",$BuildVersionValidationRegex)
$NewVersion = $VersionData[0]

$filecontent = "stuff 1.0.0.0 other stuff" #Get-Content($file)

使用链接问题中指定的捕获组替换$filecontent中的文本会导致结果不完整...

$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 捕获的点出现在这里,但多余的空间也出现在这里。

那么,我想念的是什么?或者有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

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

tl; dr

如果将 -replace与引用捕获组 PowerShell 变量的替换操作数一起使用,请使用诸如"`${<ndx>}${<PsVar>}" < / strong>,其中<ndx>是捕获组的索引,而<PsVar>是PowerShell变量的名称;请注意第一个`之前的$

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

如果您忽略使用{...}来消除捕获组索引的歧义,则替换操作会失败,因为插值的字符串值实际上会引用另一个索引:
-replace然后会看到{{ 1}},由于引用了索引为[$12]的不存在的捕获组,因此保持原样:

12

将PowerShell的字符串扩展(插值)与
PS> $var = '2'; 'foo' -replace '(f)', "[`$1$var]" [$12]oo # !! -replace saw '$12', i.e., a nonexistent group with index 12 运算符
的语法混合使用是很棘手的,因为它是容易混淆

  • 双引号-replace)字符串中,PowerShell的通用 string扩展(字符串插值)功能可解释{{1} }字符 first ,其中"..."前缀是指(PowerShell)变量,在$内是整个语句

  • 该扩展的结果是什么字符串,然后由$运算符 then 解释,其中$(...)前缀的标记是指正则表达式匹配操作的结果,如this answer所述。

  • 请注意,-replace的这些解释层是完全不相关的,并且两者都使用标记$是偶然的。

因此:

  • 如果您的替代操作数不需要需要字符串扩展,即,如果不需要引用PowerShell 变量或< em>表达式,请确保使用单引号字符串($ ,这样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*. 一起传递给$

      • -replace(反引号)是PowerShell的常规转义字符,在`字符串中,用于指示下一个字符将被 literally 接受;放在`之前,它会抑制该标记的字符串内插;例如"..."产生文字$,即变量引用未 扩展。
    • 清除对捕获组的引用 ,例如,{strong},请将其包含在"I'm `$HOME" 中-例如I'm $HOME

      • 请注意,您可能还需要使用$1来消除 PowerShell 变量名称的歧义;例如{...}必须为${1},才能成功引用变量{...}
      • 此外,它不仅与捕获组 indices 有关; 命名捕获组也可能产生歧义; 在基于"$HOME1"的替换操作数中,始终在捕获组索引/名称(和PS变量)周围使用"${HOME}1"是形成的好习惯。
    • 如果有疑问,请自行输出替换操作数,以检查$HOME最终将看到什么。

      • 在上面的示例中,单独输出"..."(应用了字符串插值步骤)会使问题更加明显:{...}

为说明后一点:

-replace

问题在于,"[`$1$var]"在字符串扩展后将[$12]视为替换操作数,并且由于没有索引为PS> $var = '2'; 'foo' -replace '(f)', "[`$1$var]" [$12]oo # !! $1 wasn't recognizes as the 1st capture group. 的捕获组,因此按原样保留它。

-replace中加上捕获组号可以解决此问题:

[$12]