根据下一行查找并替换为PowerShell

根据下一行查找并替换为PowerShell,powershell,replace,Powershell,Replace,我正试图通过PowerShell查找和替换我要替换的行的下一行上的内容。例如,以下文本文件: blahblah flimflam zimzam 如果下一行不是flimflam,请不要执行任何操作 我有一个想法,就是用“新东西”来代替“废话”,但我无法让它发挥作用。不过,我想我可能会对包含新行字符的内容感兴趣。使用带a的正则表达式,您甚至可以在不知道该行内容的情况下替换上一行: (Get-Content .\SO_53398250.txt -raw) -replace "(?sm)^[^`r`

我正试图通过PowerShell查找和替换我要替换的行的下一行上的内容。例如,以下文本文件:

blahblah flimflam zimzam 如果下一行不是
flimflam
,请不要执行任何操作

我有一个想法,就是用“新东西”来代替“废话”,但我无法让它发挥作用。不过,我想我可能会对包含新行字符的内容感兴趣。

使用带a的正则表达式,您甚至可以在不知道该行内容的情况下替换上一行:

(Get-Content .\SO_53398250.txt -raw) -replace "(?sm)^[^`r`n]+(?=`r?`nflimflam)","new stuff"|
 Set-Content .\SO_53398250_2.txt
请参阅上解释的正则表达式(使用不同的转义`n=>\n)

  • 当您使用
    System.IO.StreamReader
    时,通常更容易使用
    Get Content-Raw
    将文件作为一个单行、多行字符串完整地读入内存

    • 如果性能是一个问题,您仍然可以直接使用.NET类型,在这种情况下,
      [System.IO.File]::ReadAllText($myFile.FullName)
      是一个更简单的选择

    • 要明确指定输入文件的编码,请使用
      Get encoding-encoding
      /
      [System.IO.file]::ReadAllText($myFile.FullName,)
      ,

  • [string]
    类型的
    .Replace()
    方法仅限于文本字符串替换,因此高级匹配(例如将匹配限制为整行)不是一个选项

    • 使用PowerShell基于正则表达式的
      -replace
      操作符

    • 为了避免与PowerShell在双引号(
      “…”
      )字符串中的字符串扩展(字符串插值)混淆,通常最好使用
      -将
      替换为单引号(
      “…”
      )字符串,PowerShell将其视为文本,因此您可以关注字符串中的正则表达式构造

  • (?m)
    使用内联选项
    m
    (多行)使锚定
    ^
    /
    $
    匹配每行的开始/结束(而不是整个字符串)

  • (?=…)
    是一个前瞻性断言,它在不将匹配部分包含在整体匹配中的情况下进行匹配,因此不会被替换

  • \r?\n
    是一种与平台无关的方法,用于匹配换行符序列/字符:Windows上的CRLF(
    \r\n
    ),类Unix平台上的LF only(
    \n


此问题要求使用可重用的cmdlet,该cmdlet尽可能支持流式处理

替换字符串
语法 替换找到的字符串之前的字符串:

'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
替换找到的字符串之前的第二个字符串:

'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
替换找到的字符串后的字符串:

'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
替换找到的字符串后的第二个字符串:

'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
'One', 'Two', 'Three', 'Four', 'Five' | Replace-String T X 1
One
Two
X
X
Five
替换包含
T
的(两)个字符串之后的字符串:

'One', 'Two', 'Three', 'Four', 'Five' | Replace-String T X -1
X
X
Three
Four
Five
'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
(来自管道)
要匹配和替换的字符串流

-匹配

要在流中匹配的字符串。
请注意,
-Match
运算符用于此参数,这意味着它支持正则表达式。如果整个字符串需要匹配,请使用,例如:
-匹配“^Three$”

-更换

用于替换目标的字符串

-Offset=0

相对于要替换的匹配字符串的字符串偏移量。默认值为
0
,意思是:替换匹配的字符串

背景 此cmdlet中编程的一些背景知识:

  • Begin{…}
    Process{…}
    End{…}
    用于尽可能快地通过cmdlet传递字符串,并将其释放给管道中的下一个cmdlet。此cmdlet是为管道的中间部分设计的(例如
    Get Content$myFile | Replace String a B 1 |
    ).要利用管道:
    • 避免使用括号(如:
      ($List)|替换字符串A B
    • 避免分配输出(例如:
      $Array=…|替换字符串A B
    • 避免读取整个内容的参数(如
      Get content-Raw
  • 如果这两种情况都发生(使用负偏移量替换后方,或使用正偏移量替换前方),则需要偏移量大小的缓冲区(
    $buffer=New Object String[]([Math]::Abs($offset))
  • 为了加快进程,脚本在缓冲区中循环(
    $buffer[$Count%$Offset]
    ),而不是移动包含的项
  • 如果($Count-ge-$Offset){…
    将保留第一个输入字符串(等于偏移量),因为只有在以后才能确定是否需要替换输入字符串
  • 最后(
    end{…
    ),如果
    $Offset
    为负,则缓冲区(包含其余输入字符串)将被释放。换句话说,负偏移量(例如
    -Offset-$n
    )将缓冲
    $n
    字符串,并导致输出在输入流后面运行
    $n
    字符串

我特别在那一行添加了#伪代码注释,因为这是唯一的伪代码行。好的,你现在把它放回去了,很抱歉我的编辑部分不是你想要的。当输入包含两次
flimflam
(在彼此之后),例如:
'blahblah',flimflam',flimflam',zimzam'