【问题标题】:How can I remove all the text between matches on a line?如何删除一行中匹配项之间的所有文本?
【发布时间】:2013-07-03 23:26:22
【问题描述】:

我有这个问题:

输入文字:

this is my text text text and more text
this is my text myspace this is my text
this space is my text space this is my
this is my text this is my text
this space is my text space space myspace

假设我想搜索“空间”
我想把它作为输出:

this is my text text text and more text
space
space space
this is my text this is my text
space space space space

同一行的匹配项必须用空格分隔。
没有匹配的行必须保持原样。

所有其他搜索项相同。

今天下午我正在努力实现这一点,但没有成功。
谁能帮帮我?

【问题讨论】:

  • 这是一个棘手的问题;它必须在vim中完成吗?使用 awk 会更容易完成。
  • @Ingo,不一样,另一个问题中提出的解决方案确实删除了不匹配的行中的文本。另一个问题中提出的解决方案在匹配之间没有空格。
  • 文中Ingo指出的问题对我来说没有答案,所以请尊重这个问题。
  • @Remonn 您只需要在另一个答案中调整解决方案以保留空格(即\s),然后处理任何前导/尾随剩余空格。这是一个微不足道的修改,您至少可以参考您之前的问题并告诉您失败的地方。我不明白为什么你不能自己去那里,而是用你古怪的问题向这个网站发送垃圾邮件。

标签: regex search vim replace


【解决方案1】:

解决办法:

:g/space/s/\(.*space\).*$/\1/|s/.\{-}space/ space/g|s/^ //

解释:

这很棘手,但可以做到。但是,它不能用一个正则表达式来完成。

我们做的第一件事是在最后一次匹配之后去掉任何东西(我们实际上利用了正则表达式在默认情况下是贪婪的事实):

s/\(.*space\).*$/\1/

然后我们删除所有内部匹配之间的任何内容(注意我们在这里使用 * 的惰性版本,\{-}):

s/.\{-}space/ space/g

上一步会在结果中留下一个初始空间,所以我们去掉它:

s/^ //

幸运的是,在 vim 中,我们可以将替换与 | 字符链接在一起。所以,把它们放在一起:

:g/space/s/\(.*space\).*$/\1/|s/.\{-}space/ space/g|s/^ //

【讨论】:

  • 谢谢 Ethan,非常好的解决方案。我希望它也适用于正则表达式搜索等其他搜索。会再检查一下。
  • p.e.搜索 \d,\d\+\|\d\+ 会在您的代码中出现问题,但我对其进行了一些更改,现在它可以工作了。再次Tnx。 Tnx 也到肯特。我了解了 ^G,但发现您的代码更易于使用。
【解决方案2】:

这条棘手的线路适合你吗?

:g/space/s/space/^G/g|s/[^^G]//g|s/^G/space /g

上面的^G你需要按Ctrl-V Ctrl-G

上述命令的输出与您的示例相同,除了模式后的结尾空格(在本例中为空格)。但它很容易修复,例如在:g 行之后链接另一个s/ $//。

【讨论】:

  • 酷! ^G 是一个很好的接触,使它更加神秘,但当然任何不出现在行中的字节序列都可以。不错。
  • 谢谢肯特,我会再检查一下,看看它是否也适用于其他搜索(例如使用正则表达式代码搜索)。
  • @Remonn 它不适用于动态正则表达式。例如/r.d/ 当我将^G 恢复为关键字时,我不知道它是red or rod or rid...
【解决方案3】:

Kent 的解决方案使用了一个很好的技巧,使其仅适用于固定字符串,但它简洁而简短。 Ethan Brown 的答案更笼统,但也增加了三个步骤的复杂性。我认为可以基于the accepted answer in this very similar question开发出最好的解决方案。

与 Ethan Brown 的假设相反,这确实可以通过单个正则表达式替换来完成。就在它的丑陋中:

:g/space/s/\%(^\|\%(space \)*space\%( \%(.*space\)\@=\)\?\)\zs\%(\%(space \)*space\%( \%(.*space\)\@=\)\?\)\@!.\{-1,}\ze\%(\%(space \)*space\%( \%(.*space\)\@=\)\?\|$\)//g

当您使用我的PatternsOnText plugin 中的:DeleteExcept 命令时,它变得更具可读性:

:g/space/DeleteExcept/\%(space \)*space\%( \%(.*space\)\@=\)\?/

说明

这会删除除

之外的所有内容
  • 可能连续多次出现\%(space \)*
  • 词space
  • 当它不是该行中的最后一个匹配时,包括尾随空格,即有一个后续匹配 \%(.*space\)\@=,这样空格就不会被吞掉
  • 或在该行的最后一个匹配项之后排除(即删除)\?。

更实用的选择

虽然提出上述解决方案是一个很好的挑战,但在实践中,我也倾向于两步法,因为它更简单:

:g/space/DeleteExcept/space\%( \|$\)/

这会留下可以修剪的尾随空格

:%s/ $//

【讨论】:

  • 只是出于好奇......难道不能用 submatch(0) 来解决我的问题吗?
猜你喜欢
  • 1970-01-01
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多