每次替换字符串时增加一个数字

Incrementing a number each time it replaces a string

所以我使用的脚本看起来像这样。它工作得很好,唯一的问题是它正在计算行号,我只是想让它每次用 1 2 3 4 等替换 num ,它看起来像这样 5 20 25 等,那是因为它似乎在计数并为每一行递增 $c 而不是每次替换字符串 num.

$c=0
(Get-Content C:\Users\H\Desktop.txt) | 
Foreach-Object {$_ -replace "num", $((++$c))}  | 
Out-File C:\Users\H\Desktop.txt

试试这个:

$c = [ref] 0
$text = Get-Content 'C:\Users\H\Desktop.txt' -Raw
[regex]::Replace( $text, 'num', { (++$c.Value) } ) |
    Set-Content 'C:\Users\H\Desktop.txt'

# With PowerShell 6+ you could write:
# (Get-Content 'C:\Users\H\Desktop.txt' -Raw) -replace 'num', { (++$c.Value) } |
#    Set-Content 'C:\Users\H\Desktop.txt'

Copy-pastable 演示:

$text = @'
num foo num
bar num bar
num baz num
'@ 

$c = [ref] 0
[regex]::Replace( $text, 'num', { (++$c.Value) } )

# With PowerShell 6+ you could write:
# $text -replace 'num', { (++$c.Value) }

输出:

1 foo 2
bar 3 bar
4 baz 5

解释:

  • 使用引用类型([ref]) variable instead of a plain variable. The scriptblock passed to [regex]::Replace() or -replace(仅限PS 6+)在子作用域中运行,因此它不能修改父作用域直接。您可以修改引用类型的成员,所以这就是为什么[ref] 技巧有效。除了 [ref],您还可以使用 [PSCustomObject][Hashtable](它们都是引用类型)和计数器成员。
  • 表达式++$c.Value两边的括号是输出表达式值所必需的,默认情况下不产生输出。你已经知道了,我只是为其他访客解释一下。
  • 使用带有参数 -RawGet-Content 会更快,因为文件的内容将作为单个多行字符串输出,而不是将其每行拆分为一个字符串,代价是需要更多内存。

至于你试过的:

$_ -replace "num", $((++$c))

您正在将 表达式 而不是 脚本块 作为 RHS 参数传递给 -replace 运算符。此外,仅从 PowerShell 6 开始支持 -replace 运算符的脚本块参数。对于旧版本,您必须使用 .NET 函数 [Regex]::Replace.

此表达式在 ForEach-Object“循环”的每次迭代中计算一次, 计算 -replace 运算符之前。所以你实际上只是在计算文件的行数,而不是模式出现的次数。

只有script block的执行可以延迟。它不会在您定义它的地方立即被调用 1,但是当具有 [ScriptBlock] 参数的函数或运算符决定调用它时,可能会多次调用它当模式有多个匹配项时会发生。要定义脚本块,请使用 {},就像我在开头的示例中所做的那样。


[1] 除非您使用调用或点源运算符,例如&{'foo'}