powershell - 为什么 powershell -replace 运算符未正确包括捕获组中捕获的所有字符?
问题描述
编辑:
再次查看此问题后,我添加了第二个示例,希望能突出我的困惑被放大的地方,即有一个捕获组通过其索引 (1) 访问,而我期望的值$filecontent
巧合地也是 1 .
这个问题表明,在引用其他变量时,可以使用反引号来处理双引号字符串中的捕获组。
如果您需要在替换表达式中引用其他变量(可能),您可以使用双引号字符串并用反引号转义捕获美元
但是,我看到了一些我无法解释的有趣行为。
$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
使用链接问题中指定的捕获组替换文本会给出不完整的结果...
$filecontent -replace $VersionReplacementRegex, "`$1$NewVersion" | Write-Host
返回:118.11.8
预期:1.18.11.8
$1
但是在and之间添加一个空格$NewVersion
会产生不同但同样无益的结果..
$filecontent -replace $VersionReplacementRegex, "`$1 $NewVersion" | Write-Host
返回:1. 18.11.8
捕获的点出现在这里,但不需要的空间也出现。
在这个例子中,结果有些相似,但似乎捕获组一起得到了错误的值。
$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
那么,我错过了什么,还是有更好的方法来做到这一点?
解决方案
从过去的经验来看,在对该问题的评论中提供了关键指针的PetSerAl不会回来发布答案。
tl;博士
如果使用引用捕获组和PowerShell-replace
变量的替换操作数,请使用语法,例如 "`${<ndx>}${<PsVar>}"
,其中<ndx>
是捕获组的索引,并且<PsVar>
是 PowerShell 变量的名称;注意第`
一个之前$
:
PS> $var = '2'; 'foo' -replace '(f)', "[`${1}$var]"
[f2]oo # OK, -replace saw '${1}2'
如果您忽略使用{...}
来消除捕获组索引的歧义,则替换会发生故障,因为插值后的字符串值会有效地引用不同的索引:-replace
then sees [$12]
,由于使用 index 引用不存在的捕获组12
,因此会保持原样:
PS> $var = '2'; 'foo' -replace '(f)', "[`$1$var]"
[$12]oo # !! -replace saw '$12', i.e., a nonexistent group with index 12
将 PowerShell 的字符串扩展(插值)与-replace
operator的语法混合起来很棘手,因为很容易混淆:
在双引号( ) 字符串中,首先解释字符
"..."
的是 PowerShell 的通用字符串扩展(字符串插值)功能,其中前缀指的是 (PowerShell)变量,内部指的是整个语句。$
$
$(...)
任何字符串是该扩展的结果,然后由
-replace
运算符解释,其中$
-prefixed 标记指的是正则表达式匹配操作的结果,如本答案中所总结的那样。请注意,这些
$
解释层是完全不相关的,两者都使用印记的事实$
是偶然的。
所以:
如果您的替换操作数不需要字符串扩展,即如果不需要引用 PowerShell变量或表达式,请务必使用单引号字符串 (
'...'
),这样 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*.
如果您确实需要涉及字符串扩展:
前缀
$
字符。应该通过 to-replace
with`
`
(反引号)是 PowerShell 的通用转义字符,在"..."
字符串中它用于指示下一个字符将按字面意思获取;放在 a 之前$
,它会抑制该标记的字符串插值;例如,"I'm `$HOME"
产生 literalI'm $HOME
,即变量引用未展开。
为了消除对捕获组的引用的歧义,例如
$1
,将它们括在{...}
- 例如,${1}
- 请注意,您可能还需要使用PowerShell变量名
{...}
来消除歧义;例如必须是为了成功引用变量。"$HOME1"
"${HOME}1"
$HOME
- 此外,这不仅仅是关于捕获组索引;命名捕获组也可能产生歧义;基于in
"..."
的替换操作数,始终使用{...}
捕获组索引/名称(和 PS 变量)是一个好习惯。
- 请注意,您可能还需要使用PowerShell变量名
如果有疑问,请自行输出替换操作数,以检查
-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]
其视为替换操作数,并且由于没有带有 index 的捕获组12
,所以它保持原样。
附上捕获组号{...}
解决了这个问题:
PS> $var = '2'; 'foo' -replace '(f)', "[`${1}$var]"
[f2]oo # OK
推荐阅读
- python-3.x - 为什么打印输出在 DataFrame 到 DataFrameGroupBy 之间没有变化?
- visual-studio - 文件夹权限在使用 VS 2017 编译期间开始修改
- python - Pytesseract 无法识别图像中的数字
- arrays - 如何获取一堆相同大小的二维数组并将它们变成三个维度?
- javascript - 我无法理解这个 useEffect 是如何通过 fetch 运行的
- java - 在中央找不到工件 gnu.trove:trove:jar:3.0.3 (https://repo.maven.apache.org/maven2)
- php - PHP HTML动态创建时间课程表
- javascript - 像 Promise 一样执行 for 循环
- search - Sitecore Solr 搜索完全匹配问题
- python - 是否可以使重新采样中的移动窗口从最近的日期开始?