Regex 如何使用Vim提取文件中的所有正则表达式匹配项?
考虑以下示例:Regex 如何使用Vim提取文件中的所有正则表达式匹配项?,regex,vim,match,text-extraction,Regex,Vim,Match,Text Extraction,考虑以下示例: case Foo: ... break; case Bar: ... break; case More: case Complex: ... break: ... 比方说,我们想要检索正则表达式的所有正则表达式匹配项(整个匹配文本,或者更好的是,正则表达式的\(和\))case\([^::*\):,这应该给我们(最好是在一个新的缓冲区中)类似的信息: Foo Bar More Complex ... 另一个用例示例是从HTML文
case Foo:
...
break;
case Bar:
...
break;
case More: case Complex:
...
break:
...
比方说,我们想要检索正则表达式的所有正则表达式匹配项(整个匹配文本,或者更好的是,正则表达式的\(
和\)
)case\([^::*\):,这应该给我们(最好是在一个新的缓冲区中)类似的信息:
Foo
Bar
More
Complex
...
另一个用例示例是从HTML文件中提取一些部分,例如图像的URL
有没有一种简单的方法来绘制所有正则表达式匹配并将它们放在Vim的缓冲区中
注意:它类似于问题“”。然而,与该问题中的设置不同,我还对删除不匹配的行感兴趣,最好不要使用大型或复杂的正则表达式
:g/^case\s\L\l\+\scase.*/s/case/\r&/g
:let @a=''|g/^case\s\L\l\+:/y A
现在打开一个新的缓冲区或tmp文件,然后:
"ap
:%s_^\vcase ([^:]+):_\1_
或者,如果您不关心当前缓冲区(当然可以撤消此操作)(针对复杂示例进行了更新):
在一件作品中,有一种收集图案匹配的通用方法 文本的格式。这项技术利用了具有
:substitute
命令的表达式功能
(请参见:帮助子替换-\=
)。关键的想法是使用替换
枚举所有模式匹配以计算表达式存储
他们不需要更换
首先,让我们考虑保存火柴。为了保持顺序
对于匹配的文本片段,可以方便地使用列表
(请参见帮助列表)。但是,无法修改列表
直接使用:let
命令,因为无法
在表达式中运行Ex命令(包括\=
替换表达式)。
然而,我们可以调用其中一个函数来修改列表。对于
例如,add()
函数用于将给定项附加到
指定的列表(请参见帮助添加())
另一个问题是如何在运行时避免文本修改
替代品。一种方法是使模式始终具有
通过预加\ze
或在其上附加\zs
原子进行零宽度匹配
(请参见:help/\zs
,:help/\ze
)。图案以这种方式修改
捕获事件发生之前或之后的空字符串
文本中的原始模式(此类匹配称为零宽度匹配
在Vim中;请参见:帮助/zero width
)。然后,如果替换文本也是
空的,替代实际上什么都没有改变:它只是替换
具有空字符串的零宽度匹配
由于add()
函数以及大多数列表
函数,返回对已更改列表的引用,用于我们的技术
为了工作,我们需要从中获得一个空字符串。最简单的
方法是通过指定一个范围从中提取一个长度为零的子列表
指开始索引大于结束索引的索引
结合上述想法,我们获得以下Ex命令:
:let t=[] | %s/\<case\s\+\(\w\+\):\zs/\=add(t,submatch(1))[1:0]/g
虽然不可能编写一行代码来完成示例,但很难以交互方式键入命令,例如
:%s/case\([^::]*\):/\=…/
我更喜欢使用以下步骤:
/
检查正则表达式是否与预期行匹配。
例如:
/^\s*\如何使用vim regex从以下行中提取单词,因为“help”可能是任何类似“rust”或“perlang”的单词。
vim:tw=78:ts=8:ft=help:norl:
解决方案:
let foo = substitute(foo, '^\s*vim:.*:ft=\([a-z]\+\).*:\s*$', '\1', '')
echo "foo: '" . foo . "'"
foo: 'help'
打印:
let foo = substitute(foo, '^\s*vim:.*:ft=\([a-z]\+\).*:\s*$', '\1', '')
echo "foo: '" . foo . "'"
foo: 'help'
大师冥想:这里发生了什么事?
取变量foo
中的字符串,并将其匹配以断言行的开头,然后是任意数量的空格、文字vim
和文字冒号,然后是任意数量的字符,后跟冒号ft=
和任何带字母的单词,然后是任意字符,并断言行以冒号结尾。将所有这些内容放入名为1的寄存器中,然后将其返回到参数2中,substitute
接受并用替换前面的字符串
一般来说,屏幕上任何长度超过手指的正则表达式都是一个巨大的失败,因此请降低屏幕分辨率,直到它合适为止。作为ib公认答案的一个小补充,它也可以正常工作。似乎标志n
足以避免不必要的替换问题
:let t=[] | %s/\<case\s\+\(\w\+\):/\=add(t,submatch(1))/gn
:让t=[]|%s/\你是指反向引用吗:%s/^\vcase([^::]+):/\1/
使用\1
获取第一个捕获组。如果您只想将这些组提取到一个新文件中(您的问题不清楚),您可以使用sed或grep更轻松地执行此操作;sed示例:sed-n'/^\s*case\s\+/{s/\s*case\s\+\([^::\+\):/\1/;p}文件
@beerbajay:在新文件中可以。我同意sed会做得很好,只是我需要启动一个命令提示符并再次找到文件,所以我正在寻找一个Vim解决方案。@mathematic.coffee:一点也不。问题不是搜索和替换(除非包含新行),而是抓取所有匹配项并将它们放入另一个缓冲区。这与此问题非常相似:在第一个截取的代码中列出的命令中肯定存在一些错误。您在发布之前运行过它们吗?这两个命令都不会运行!您可能的意思是:let@a=''g/^case\s\L\L+:/y A
:v/../d
或:g!//d
是一个很好的技巧,因此它会删除所有不匹配的行。然而,它并不是真正严格的正则表达式匹配。它提取匹配行,然后假设每行有一个匹配项,第二次搜索和替换将起作用。这在一般情况下是行不通的。我会更新我的样本。@ib。谢谢你指出,你说得对。当我在windows上,在excel前面时会发生这种情况。。。更新答案。@Wernight,好的,我已经为你的特殊情况更新了我的答案。回答得好。我特别喜欢这个小男孩