问题
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 (|
) stringAROUND LINE
or stringLINE2
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