每次替换字符串时增加一个数字
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
两边的括号是输出表达式值所必需的,默认情况下不产生输出。你已经知道了,我只是为其他访客解释一下。
- 使用带有参数
-Raw
的 Get-Content
会更快,因为文件的内容将作为单个多行字符串输出,而不是将其每行拆分为一个字符串,代价是需要更多内存。
至于你试过的:
$_ -replace "num", $((++$c))
您正在将 表达式 而不是 脚本块 作为 RHS 参数传递给 -replace
运算符。此外,仅从 PowerShell 6 开始支持 -replace
运算符的脚本块参数。对于旧版本,您必须使用 .NET 函数 [Regex]::Replace
.
此表达式在 ForEach-Object
“循环”的每次迭代中计算一次,在 计算 -replace
运算符之前。所以你实际上只是在计算文件的行数,而不是模式出现的次数。
只有script block的执行可以延迟。它不会在您定义它的地方立即被调用 1,但是当具有 [ScriptBlock]
参数的函数或运算符决定调用它时,可能会多次调用它当模式有多个匹配项时会发生。要定义脚本块,请使用 {}
,就像我在开头的示例中所做的那样。
[1] 除非您使用调用或点源运算符,例如&{'foo'}
所以我使用的脚本看起来像这样。它工作得很好,唯一的问题是它正在计算行号,我只是想让它每次用 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
两边的括号是输出表达式值所必需的,默认情况下不产生输出。你已经知道了,我只是为其他访客解释一下。 - 使用带有参数
-Raw
的Get-Content
会更快,因为文件的内容将作为单个多行字符串输出,而不是将其每行拆分为一个字符串,代价是需要更多内存。
至于你试过的:
$_ -replace "num", $((++$c))
您正在将 表达式 而不是 脚本块 作为 RHS 参数传递给 -replace
运算符。此外,仅从 PowerShell 6 开始支持 -replace
运算符的脚本块参数。对于旧版本,您必须使用 .NET 函数 [Regex]::Replace
.
此表达式在 ForEach-Object
“循环”的每次迭代中计算一次,在 计算 -replace
运算符之前。所以你实际上只是在计算文件的行数,而不是模式出现的次数。
只有script block的执行可以延迟。它不会在您定义它的地方立即被调用 1,但是当具有 [ScriptBlock]
参数的函数或运算符决定调用它时,可能会多次调用它当模式有多个匹配项时会发生。要定义脚本块,请使用 {}
,就像我在开头的示例中所做的那样。
[1] 除非您使用调用或点源运算符,例如&{'foo'}