Regex/Vim:匹配除模式之外的所有内容,其中模式是多行的

  • 本文关键字:模式 Regex Vim regex vim
  • 更新时间 :
  • 英文 :


Vim中是否有方法执行与类似的操作

:v/PATTERN/d 

其中PATTERN是多行正则表达式模式?我确信在脚本中有一种方法可以做到这一点,但我主要想知道是否可以只使用标准的regex替换或Vim命令,因为在这一点上,它更具学术性,而不是实际需要。

我的例子如下:

asdf
begin
   blah
end
asdf
alsdfjasf
begin
   random stuff
end
...

我想得到开始/结束的块,它们之间有线,但忽略块之外的一切,最终以结束

begin
   blah
end
begin
   random stuff
end
...

我的想法是做

:v/begin_.{-}end/d 

如果所有内容都不匹配,则会被删除,甚至复制到寄存器,但显然:v和:g只能在单行上工作。

然后,我开始运行一个替换,并用与begin_.{-}end模式不匹配的空字符串替换所有内容,但我无法理解如何使用look-behinds或任何东西来实现这一点。正则表达式在搜索时工作得很好,但我不知道如何告诉正则表达式引擎找到除该模式之外的所有内容。有什么想法吗?

清除reg a

qaq

begin...end附加到reg a

:g/begin/,/end/y A

打开新选项卡

:tabnew

放入reg a

"ap

将其从内向外翻转,并删除由以下模式分隔的所有内容:

:%s/%(^endn*|%^)zs_.{-}ze%(^begin|%$)//
  • %( ... )-非捕获组
  • ^endn*-你的模式结束
  • %^-文件的开头
  • zs-在要替换的字符串中不包括在此点之前匹配的任何内容
  • _.{-}-任何东西的非贪婪匹配(包括换行符)
  • ze-不要在要替换的字符串中包含任何在此点之后匹配的内容
  • ^begin-你模式的开始
  • %$-你的模式结束

g和v执行的命令本身可以具有范围,因此您可以使用:g /begin/ .,/end/xxx对从"开始"到"结束"的所有内容执行操作,其中xxx是要在该范围上执行的命令。你真的不能把它用于:v,但有几种方法可以在多次通过中做到这一点,例如

"mark all the lines we want to keep by putting '@' at the start of the line"
:g/^begin/ .,/^end/  s/^/@/
"delete all unmarked lines"
:v/^@/ d
"remove the markers"
:s/^@//

当然,这是假设文件中没有任何以@开头的行。

或者,您可以删除每个"结束"和下一个"开始"之间的所有内容

:g/^end/ +1,/^begin/-1 d

然后删除留在文件开头和结尾的cruft:

:1,/^begin/-1 d
:$?^end?+1,$ d

注意使用$?^end?+1从文件末尾向后搜索,以找到以"end"开头的最后一行。

注意:如果文件以"begin"开头或以"end"结尾,那么最后两个会删除太多内容,所以在使用它们之前请检查。

最新更新