В этом вопросе запрашивается многоразовый командлет, который поддерживает максимально возможную потоковую передачу ...
Replace-String
Function Replace-String {
[CmdletBinding()][OutputType([String[]])]Param (
[String]$Match, [String]$Replacement, [Int]$Offset = 0,
[Parameter(ValueFromPipeLine = $True)][String[]]$InputObject
)
Begin {
$Count = 0
$Buffer = New-Object String[] ([Math]::Abs($Offset))
}
Process {
$InputObject | ForEach-Object {
If ($Offset -gt 0) {
If ($Buffer[$Count % $Offset] -Match $Match) {$Replacement} Else {$_}
} ElseIf ($Offset -lt 0) {
If ($Count -ge -$Offset) {If ($_ -Match $Match) {$Replacement} Else {$Buffer[$Count % $Offset]}}
} Else {
If ($_ -Match $Match) {$Replacement} Else {$_}
}
If ($Offset) {$Buffer[$Count++ % $Offset] = $_}
}
}
End {
For ($i = 0; $i -gt $Offset; $i--) {$Buffer[$Count++ % $Offset]}
}
}
Синтаксис
$InputObject | Replace-String [-Match] <String to find>
[-Replacement] <Replacement string to use>
[-Offset] <Offset relative to the matched string>
Примеры:
Заменить найденную строку:
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String Three X 0
One
Two
X
Four
Five
Заменить строку перед найденной строкой:
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String Three X -1
One
X
Three
Four
Five
Заменить вторую строку перед найденной строкой:
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String Three X -2
X
Two
Three
Four
Five
Заменить строку после найденной строки:
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String Three X 1
One
Two
Three
X
Five
Заменить вторую строку после найденной строки:
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String Three X 2
One
Two
Three
Four
X
Заменить строки до (двух) строк, которыесодержит T
:
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String T X -1
X
X
Three
Four
Five
Заменить строки после (двух) строк, содержащих T
:
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String T X 1
One
Two
X
X
Five
Специфично для вопроса:
'blahblah', 'flimflam','zimzam' | Replace-String 'flimflam' 'new stuff' -1
new stuff
flimflam
zimzam
Параметры
-InputObject <String[]>
(из конвейера)
Поток строк для сопоставления и замены
-Match <String>
Строка для сопоставления в потоке.
Обратите внимание, что для этого параметра используется оператор -Match
, что означает, что он поддерживает регулярные выражения.Если вся строка должна совпадать, используйте метки начала и конца строки , например: -Match '^Three$'
.
-Replacement <String>
Используемая строкадля замены цели.
-Offset <Int> = 0
Смещение строки относительно совпадающей строки (строк) для замены.По умолчанию это 0
, что означает: заменить соответствующие строки.
Фон
Небольшой фон программирования в этом командлете:
- Методы обработки ввода (
Begin {...}
, Process {...}
, End {...}
используются для максимально быстрой передачи строк через командлет и освобождения их для следующего командлета в конвейере. Этот командлет предназначен длясередина конвейера (например, Get-Content $myFile | Replace-String A B 1 | ...
). Чтобы использовать из конвейера: - Избегайте скобок (например:
($List) | Replace-String A B
- Избегайте назначения вывода (например,:
$Array = ... | Replace-String A B
- Избегайте параметров, которые читают весь контент (как
Get-Content -Raw
)
- Если обаВ случаях (замена позади - с использованием отрицательного смещения - или впереди - с использованием положительного смещения-) требуется буфер с размером смещения (
$Buffer = New-Object String[] ([Math]::Abs($Offset))
) - Для ускорения процесса сценарий циклически повторяетсячерез буфер (
$Buffer[$Count % $Offset]
) вместо смещения содержащихся элементов If ($Count -ge -$Offset) {...
будет содержать первый нюmber входных строк (равно смещению), поскольку только позже можно определить, нужно ли заменить входную строку - В конце (
End {...
), если $Offset
отрицательно,буфер (содержащий остальные входные строки) освобождается.Другими словами, отрицательное смещение (например, -offset -$n
) будет буферизовать строки $n
и заставлять вывод запускать строки $n
позади входного потока