为什么 powershell -replace 运算符没有正确包含捕获组中捕获的所有字符? [英] Why is powershell -replace operator not properly including all characters captured in the capture group?

查看:25
本文介绍了为什么 powershell -replace 运算符没有正确包含捕获组中捕获的所有字符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

再次查看此问题后,我添加了第二个示例,希望能突出显示我的困惑被放大的地方,即有一个捕获组通过其索引 (1) 访问,以及我期望从 $filecontent 巧合的是也是 1.

After reviewing this question again, I've added a second example that I hope will highlight where my confusion became amplified, namely there was one capture group accessed by its index (1), and the value I expected from the $filecontent was coincidentally also a 1.

这个问题表示可以使用反勾号来解决双引号中的捕获组引用其他变量时引用的字符串.

This question indicates that a back tick can be used to address capture groups in a double quoted string when referencing other variables.

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

If you need to reference other variables in your replacement expression (as you may), you can use a double-quoted string and escape the capture dollars with a backtick

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

However, I'm seeing some interesting behavior that I can't explain.

$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 中的文本会产生不完整的结果...

replacing text in $filecontent using the capture group as specified in the linked question gives an incomplete result...

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

返回:118.11.8预期:1.18.11.8

但是在 $1$NewVersion 之间添加一个空格会产生不同但同样无益的结果..

But adding a space between the $1 and $NewVersion gives a different yet equally unhelpful result..

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

返回:<代码>1.18.11.8捕获的点出现在此处,但不需要的空间也会出现.

returns: 1. 18.11.8 The captured dot appears here, but so does the undesirable space.

在这个例子中,结果有些相似,但似乎捕获组一起得到了错误的值.

With this example, the results are somewhat similar, but it seems that the capture group is getting the wrong value all together.

$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

Adding the space in the replacement string returns: 5. 18.11.8

那么,我错过了什么,或者有更好的方法来做到这一点?

So, what am I missing, or is there a better way to do this?

推荐答案

从以往的经验来看,PetSerAl,在对该问题的评论中提供了关键指针,不会回来发布答案.

Judging from past experience, PetSerAl, who provided the crucial pointer in a comment on the question, won't be back to post an answer.

tl;dr

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

If you use -replace with a replacement operand that references capture groups and PowerShell variables, use syntax such as "`${<ndx>}${<PsVar>}", where <ndx> is the index of your capture group, and <PsVar> is the name of your PowerShell variable; note the ` before the first $:

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

如果您忽略使用 {...} 来消除捕获组索引的歧义,则替换会发生故障,因为插入的字符串值随后有效地引用了不同的索引:
-replace 然后看到 [$12],由于引用了索引为 12 的不存在的捕获组,所以保持原样:

If you neglect to use {...} to disambiguate the capture-group index, the replacement malfunctions, because the interpolated string value then effectively references a different index:
-replace then sees [$12], which, due to referring to a nonexistent capture group with index 12, is left as-is:

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

<小时>

将 PowerShell 的字符串扩展(插值)与
-replace 运算符
的语法混合使用是很棘手的,因为它是容易混淆:


It is tricky to mix PowerShell's string expansion (interpolation) with the syntax of the
-replace operator
, because it is easy to get confused:

  • 双引号("...")字符串中,它是PowerShell的通用字符串扩展(字符串插值)解释 $ 字符 first 的功能,其中 $ 前缀指的是(PowerShell)变量,并且在 $(...),整个语句.

  • In double-quoted ("...") strings, it is PowerShell's generic string expansion (string interpolation) feature that interprets $ chars first, where a $ prefix refers to (PowerShell) variables and, inside $(...), entire statements.

无论那个扩展的 result 是什么字符串,then 都会被 -replace 操作符解释,其中 $-prefixed 标记指的是正则表达式匹配操作的结果,如这个答案中所述a>.

Whatever string is the result of that expansion is then interpreted by the -replace operator, where $-prefixed tokens refer to results of the regex-matching operation, as summarized in this answer.

请注意,这些 $ 解释层是完全不相关的,并且两者都使用符号 $ 是偶然的.

Note that these layers of $ interpretation are entire unrelated and the fact that both use sigil $ is incidental.

因此:

  • 如果您的替换操作数不需要字符串扩展,即如果不需要引用 PowerShell 变量表达式,一定要使用单引号字符串('...'),这样PowerShell的字符串扩展没有发挥作用:

  • If your replacement operand doesn't need string expansion, i.e., if there's no need to reference PowerShell variables or expressions, be sure to use a single-quoted string ('...'), so that PowerShell's string expansion doesn't come into play:

 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*.

  • 如果您确实需要涉及字符串扩展:

  • If you do need to involve string expansion:

    • 前缀 $ 字符. 应该传递给 -replace with `

    • Prefix $ chars. that should be passed through to -replace with `

    • `(反引号)是PowerShell的通用转义字符,在"..."字符串中,它用于指示要取下一个字符字面意思;放在 $ 之前,它会禁止该标记的字符串插值;例如,"I'm `$HOME" 产生文字 I'm $HOME,即变量引用没有扩展.
    • ` (the backtick) is PowerShell's general escape character, and in "..." strings it is used to indicate that the next character is to be taken literally; placed before a $, it suppresses string interpolation for that token; e.g., "I'm `$HOME" yields literal I'm $HOME, i.e., the variable reference was not expanded.

    为了消除对捕获组的引用,例如$1将它们括在{...} - 例如,${1}

    • 请注意,您可能还需要使用 {...} 来消除 PowerShell 变量名称的歧义;例如"$HOME1" 必须是 "${HOME}1" 才能成功引用变量 $HOME.
    • 此外,这不仅仅是关于捕获组索引命名捕获组也可能出现歧义;在基于 "..." 的替换操作数中,总是在捕获组索引/名称(和 PS 变量)周围使用 {...} 是一个很好的选择养成习惯.
    • Note that you may also need to use {...} to disambiguate PowerShell variable names; e.g. "$HOME1" must be "${HOME}1" in order to reference variable $HOME successfully.
    • Also, it is not just about capture-group indices; ambiguity can also arise with named capture groups; in "..."-based replacement operands, always using {...} around capture-group indices / names (and PS variables) is a good habit to form.

    如果有疑问,请自行输出替换操作数,以检查 -replace 最终会看到什么.

    If in doubt, output the replacement operand by itself in order to inspect what -replace will ultimately see.

    • 在上面的例子中,输出 "[`$1$var]" 本身,应用字符串插值步骤,会使问题更加明显:[$12]
    • In the example above, outputting "[`$1$var]" by itself, which applies the string-interpolation step, would have made the problem more obvious: [$12]

    为了说明后一点:

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

    问题是-replace,在字符串扩展后,看到[$12]作为替换操作数,并且因为没有索引12的捕获组,它保持原样.

    The problem was that -replace, after string expansion, saw [$12] as the replacement operand, and since there was no capture group with index 12, it was left as-is.

    将捕获组编号包含在 {...} 中解决了问题:

    Enclosing the capture-group number in {...} solves the problem:

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

    这篇关于为什么 powershell -replace 运算符没有正确包含捕获组中捕获的所有字符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆