Powershell5 通过组合 foreach、begin、process 和 replace 命令来压缩代码
Powershell5 Compact code by combining foreach, begin, process, and replace command
我可以用更少的代码得到相同的结果吗?
代码搜索 sample.bat 字符串 AROUND LINE {1-9999} 和 LINE2 {1-9999} 并将 {1-9999} 替换为代码所在的 {line number}。
sample.bat:
AROUND LINE 262
LINE2 1964
旧代码:
gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
$_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
$lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat
(gc $env:temp\results.bat) | foreach -Begin {$lc = 1} -Process {
$_ -replace "LINE2 \d*", "LINE2 $lc";
$lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat
当前代码:
(gc $env:temp\sample.bat) | foreach -Begin {$lc = 1} -Process {
$_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
$lc += 1
} | foreach -Begin {$lc = 1} -Process {
$_ -replace "LINE2 \d*", "LINE2 $lc";
} | Out-File -Encoding Ascii $env:temp\sample.bat
预期结果:
AROUND LINE 1
LINE2 2
实际结果:
AROUND LINE 1
LINE2 2
您可以使用一个正则表达式完成这项工作:
gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
$_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++
} | Set-Content -Encoding Ascii $env:temp\results.bat
请注意,我使用 '...'
(单引号)而不是 "..."
(双引号)来括起正则表达式,这样可以更好地排除可能引起的混淆从 PowerShell 首先执行字符串扩展(插值)。
$lc++
returns 当前 $lc
值并在之后将其递增 1
,从而无需 $lc += 1
语句。
此外,我已将 Out-File
替换为 Set-Content
,因为它们在保存 字符串 方面的功能相同,但后者更快。
最后,要匹配一个或多个数字,请使用\d+
而不是\d*
。
关于 $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++
的注释:
正则表达式 (?<=AROUND LINE |LINE2 )\d+
使用后视断言 ((?<=...)
来查找 (|
) 字符串 AROUND LINE
或字符串 LINE2
在一位或多位 (+
) 位 (\d
) 之前。
- 后视断言在设计上不被视为匹配的一部分,因此被替换的子字符串仅限于 运行 位数字,即仅 数字.
$lc++
是替换操作数:它 returns 变量 $lc
的当前值并在 之后增加它的值 ;请注意,即使 $lc
是一个 数字 ([int]
),PowerShell 会自动将其转换为字符串以进行替换。
不过,一般来说,您可以简单地 链 -replace
操作:
# ...
$_ -replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc"
++$lc
# ...
我可以用更少的代码得到相同的结果吗? 代码搜索 sample.bat 字符串 AROUND LINE {1-9999} 和 LINE2 {1-9999} 并将 {1-9999} 替换为代码所在的 {line number}。
sample.bat:
AROUND LINE 262
LINE2 1964
旧代码:
gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
$_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
$lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat
(gc $env:temp\results.bat) | foreach -Begin {$lc = 1} -Process {
$_ -replace "LINE2 \d*", "LINE2 $lc";
$lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat
当前代码:
(gc $env:temp\sample.bat) | foreach -Begin {$lc = 1} -Process {
$_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
$lc += 1
} | foreach -Begin {$lc = 1} -Process {
$_ -replace "LINE2 \d*", "LINE2 $lc";
} | Out-File -Encoding Ascii $env:temp\sample.bat
预期结果:
AROUND LINE 1
LINE2 2
实际结果:
AROUND LINE 1
LINE2 2
您可以使用一个正则表达式完成这项工作:
gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
$_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++
} | Set-Content -Encoding Ascii $env:temp\results.bat
请注意,我使用 '...'
(单引号)而不是 "..."
(双引号)来括起正则表达式,这样可以更好地排除可能引起的混淆从 PowerShell 首先执行字符串扩展(插值)。
$lc++
returns 当前 $lc
值并在之后将其递增 1
,从而无需 $lc += 1
语句。
此外,我已将 Out-File
替换为 Set-Content
,因为它们在保存 字符串 方面的功能相同,但后者更快。
最后,要匹配一个或多个数字,请使用\d+
而不是\d*
。
关于 $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++
的注释:
正则表达式
(?<=AROUND LINE |LINE2 )\d+
使用后视断言 ((?<=...)
来查找 (|
) 字符串AROUND LINE
或字符串LINE2
在一位或多位 (+
) 位 (\d
) 之前。- 后视断言在设计上不被视为匹配的一部分,因此被替换的子字符串仅限于 运行 位数字,即仅 数字.
$lc++
是替换操作数:它 returns 变量$lc
的当前值并在 之后增加它的值 ;请注意,即使$lc
是一个 数字 ([int]
),PowerShell 会自动将其转换为字符串以进行替换。
不过,一般来说,您可以简单地 链 -replace
操作:
# ...
$_ -replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc"
++$lc
# ...