我对以下替换语句有一个理解问题。
'Select {0}' -replace '[^\\](\{0\})', 'Success'
我希望:选择成功
相反,结果是:SelectSuccess
'[^\\](\{0\})'
模式可以通过以下方式解构:
如果我删除了非部分[^\\]
。然后结果再次成为选择成功
我错过了什么吗?
正如LotPings在评论中指出的那样,问题是[^\\]
匹配{0}
之前的空格字符,因此被替换的完整匹配是 {0}
,这解释了为什么结果是SelectSuccess
。
解决方案是使用negative look-behind assertion:
Select {0}' -replace '(?<!\\)\{0\}', 'Success'
(?<!\\)
确保子表达式\{0\}
不是(!
),前面是((?<...
)\
char。 (\\
)不包括那个字符。在比赛中。
正如LotPings也指出的那样,你在正则表达式中使用捕获组((...)
)没有任何效果,因为你既没有将它称为正则表达式(\1
)本身内的反向引用,也没有将其称为替换操作数($1
)。
请注意,无论捕获组如何,-replace
总是取代正则表达式整体捕获的内容。要匹配输入的部分而不将其包含在捕获的结果中,请使用look-around assertions,如上所示。
编者注:这个答案显示了PowerShell中可用的一般字符串格式化技术,但在OP的特定情况下,它的使用不是一个选项,因为需要条件字符串替换。
你知道-f
的operator.of吗? PowerShell能够像在.net中一样进行字符串格式化。
例:-
'Select {0}' -f 'Success'
'Select {0} {1}' -f 'All','Files'
请参阅下面的文章,了解它是如何在.Net中完成的,同样可以使用-f
完成
https://docs.microsoft.com/en-us/dotnet/api/system.string.format?view=netframework-4.7.2#examples
你想做两件事:
{0}
不是以逃脱的{
开始,考虑到在\\
之前可以有一个{
表示字面反斜杠(使用(?<=(?<!\\)(?:\\{2})*)\{0\}
正则表达式并用Success
替换)(?s)\\(.)
正则表达式并替换为$1
)使用
'Select \\\{0}' -replace '(?<=(?<!\\)(?:\\{2})*)\{0\}', 'Success' -replace '(?s)\\(.)', '$1'
模式1详细信息
(?<=(?<!\\)(?:\\{2})*)
- 一个正面的背后,立即在当前位置的左侧,需要
(?<!\\)
- 没有\
立即允许在当前位置的左侧
(?:\\{2})*
- 重复0次或更多次双反斜杠\{0\}
- {0}
字符串。模式2细节
(?s)
- 一个RegexOptions.Singleline
选项,使.
能够匹配换行\\
- 一个字面反斜杠(.)
- 捕获组1:任何字符(在匹配替换后它将被放回到结果字符串中)。