如何使用易于阅读且易于使用 PowerShell 5 添加/修改/删除的搜索字符串来修改 Windows ascii 文本文件中的字符串(LINE2“行号 LINE2 is on”)。此脚本将解析 2500 行文件,找到 139 个字符串实例,替换它们并覆盖原始字符串,平均耗时不到 165 毫秒,具体取决于您使用的方法。哪种方法更快?哪种方法更容易添加/修改/删除字符串?
搜索字符串“AROUND LINE {1-9999}”和“LINE2 {1-9999}”,并将 {1-9999} 替换为代码所在的{行号}。测试是使用 2500 行文件而不是两行sample.bat 完成的。
Sample.bat 包含两行:
ECHO AROUND LINE 5936
TITLE %TIME% DISPLAY TCP-IP SETTINGS LINE2 5937
方法一:使用 Get-Content + -replace + Set-Content:
Measure-command {
copy-item $env:temp\sample9.bat -d $env:temp\sample.bat -force
(gc $env:temp\sample.bat) | foreach -Begin {$lc = 1} -Process {
$_ -replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc"
++$lc
} | sc -Encoding Ascii $env:temp\sample.bat}
结果:十次运行为 175ms-387ms,平均为 215ms。
您可以通过添加/删除/修改 -replace 来修改搜索。
-replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc" -replace 'PLACEMARK \d+', "PLACEMARK $lc"
powershell $env:temp\sample.ps1 $env:temp\sample.bat:
(gc $args[0]) | foreach -Begin {$lc = 1} -Process {
$_ -replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc"
++$lc
} | sc -Encoding Ascii $args[0]
方法二:使用 switch 和 .NET 框架:
Measure-command {
copy-item $env:temp\sample9.bat -d $env:temp\sample.bat -force
$file = "$env:temp\sample.bat"
$lc = 0
$updatedLines = switch -Regex ([IO.File]::ReadAllLines($file)) {
'^(.*? (?:AROUND LINE|LINE2) )\d+(.*)$' { $Matches[1] + ++$lc + $Matches[2] }
default { ++$lc; $_ }
}
[IO.File]::WriteAllLines($file, $updatedLines, [Text.Encoding]::ASCII)}
结果:十次运行 73ms-816ms,平均 175ms。
方法三:使用基于预编译正则表达式的 switch 和 .NET 框架优化版本:
Measure-command {
copy-item $env:temp\sample9.bat -d $env:temp\sample.bat -force
$file = "$env:temp\sample.bat"
$regex = [Regex]::new('^(.*? (?:AROUND LINE|LINE2) )\d+(.*)$', 'Compiled, IgnoreCase, CultureInvariant')
$lc = 0
$updatedLines = & {foreach ($line in [IO.File]::ReadLines($file)) {
$lc++
$m = $regex.Match($line)
if ($m.Success) {
$g = $m.Groups
$g[1].Value + $lc + $g[2].Value
} else { $line }
}}
[IO.File]::WriteAllLines($file, $updatedLines, [Text.Encoding]::ASCII)}
结果:十次运行为 71ms-236ms,平均为 106ms。
添加/修改/删除您的搜索字符串:
AROUND LINE|LINE2|PLACEMARK
AROUND LINE|LINE3
LINE4
powershell $env:temp\sample.ps1 $env:temp\sample.bat:
$file=$args[0]
$regex = [Regex]::new('^(.*? (?:AROUND LINE|LINE2) )\d+(.*)$', 'Compiled, IgnoreCase, CultureInvariant')
$lc = 0
$updatedLines = & {foreach ($line in [IO.File]::ReadLines($file
)) {
$lc++
$m = $regex.Match($line)
if ($m.Success) {
$g = $m.Groups
$g[1].Value + $lc + $g[2].Value
} else { $line }
}}
[IO.File]::WriteAllLines($file
, $updatedLines, [Text.Encoding]::ASCII)
Editor's note: This is a follow-up question to Iterate a backed up ascii text file, find all instances of {LINE2 1-9999} replace with {LINE2 "line number the code is on"}. Overwrite. Faster?
The evolution of this question from youngest to oldest:
1. 54757890 2. 54737787 3. 54712715 4. 54682186
Update: I've used @mklement0 regex solution.