Powershell5 Compact code by combining foreach, begin, process, and replace command

房东的猫 提交于 2020-01-02 19:10:36

问题


Can I get the same results with less code? The code searches sample.bat for the strings AROUND LINE {1-9999} and LINE2 {1-9999} and replaces {1-9999} with the {line number} the code is on.

sample.bat:

AROUND LINE 262
LINE2 1964

Old code:

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

Current code:

(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

Expected results:

AROUND LINE 1
LINE2 2

Actual results:

AROUND LINE 1
LINE2 2

回答1:


You can make this work with a single regex:

gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
  $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++
} | Set-Content -Encoding Ascii $env:temp\results.bat

Note that I'm using '...' (single quotes) rather than "..." (double quotes) to enclose the regex, which is preferable to rule out potential confusion arising from PowerShell performing string expansion (interpolation) first.
$lc++ returns the current $lc value and increments it by 1 afterwards, obviating the need for the $lc += 1 statement.
Also, I've replaced Out-File with Set-Content, as they're functionally the same for saving strings, but the latter is faster.
Finally, to match one or more digits, use \d+ rather than \d*.

A note on $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++:

  • Regex (?<=AROUND LINE |LINE2 )\d+ uses a look-behind assertion ((?<=...) to look for either (|) string AROUND LINE  or string LINE2 before one or more (+) digits (\d).

    • The look-behind assertion is by design not considered part of the match, so that the substring getting replaced is limited to the run of digits, i.e., the number only.
  • $lc++ is the replacement operand: it returns the current value of variable $lc and increments its value afterwards; note that even though $lc is a number ([int]), PowerShell automatically converts it to a string for the replacement.


Generally, though, you can simply chain -replace operations:

# ...
$_ -replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc"
++$lc
# ... 


来源:https://stackoverflow.com/questions/54757890/powershell5-compact-code-by-combining-foreach-begin-process-and-replace-comma

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!