为什么我不能在 PowerShell 的替换运算符中转换匹配令牌?

Why can't I transform the match token in PowerShell's replace operator?

试图简化一些 PowerShell 字符串替换代码,遇到了一些我无法解释的问题。明确地说,我知道如何找到一个子字符串并将 it/transform 替换为另一个值。 我在这里要求的是对这种行为的解释以及为什么它不能这样工作。

对于常规字符串,无论它是变量还是硬编码,我都可以在呈现后按照我认为合适的方式修改字符串。例如:

($greeting = 'HELLO'.ToLower()) # ===> hello

这通过返回字符串的小写副本产生预期的输出。但是,我使用 -replace 运算符进行了尝试,得到了一个有趣的结果:

$greeting -replace '\w+', '[=11=]'.ToUpper() # ===> hello

我原以为字符串中的匹配模式会被替换为匹配项的大写副本,但这并没有发生。我尝试了其他一些越来越丑陋的方法,看看是否有某种方法可以让它工作但无济于事:

$greeting -replace '\w+', ('[=12=]').ToUpper() # ===> hello
$greeting -replace '\w+', "$(('[=12=]').ToUpper())" # ===> hello
$greeting -replace '\w+', "`[=12=]".ToUpper() # === hello
$greeting -replace '\w+', '`[=12=]'.ToString().ToUpper() # ===> hello
$greeting -replace '\w+', (('[=12=]').ToString()).ToUpper() # ===> hello

我也尝试用 -creplace 代替 -replace 来处理其中的一些,但这也没有任何效果。为什么在使用 PowerShell 的 -replace 运算符时无法转换匹配结果?

我使用 PowerShell 5.1 和 7 对此进行了测试,因此此行为在 MS PowerShell 和 PowerShell Core 之间扩展。

ToUpper() 之前执行 结果 upper-case 字符串作为替代参数传递给 -replace - 而 upper-case 版本的 [=14=] 只是 [=14=],因此与完全省略 .ToUpper() 没有什么不同。

如果您希望将 ToUpper() 作为替换例程的一部分调用,您必须将 pass a scriptblock 作为替换参数:

$greeting -replace '\w+', {$_.Value.ToUpper()}

这仅适用于 PowerShell 6.2 及更高版本,在 Windows PowerShell 中您必须直接调用 [regex]::Replace()

[regex]::Replace($greeting, '\w+', {param($m) $m.Value.ToUpper()})