【问题标题】:Modifying a line matching pattern and all following lines starting with character in Vim在 Vim 中修改行匹配模式和所有以字符开头的行
【发布时间】:2020-07-15 14:33:59
【问题描述】:

我必须在与模式(例如字符串“foo”)匹配的行前面加上字符“*”以及以下所有以“+”开头的行。

在我正在处理的文件中,语法使用“+”作为一行的第一个字符,表示该行是前一行的一部分,例如:

this is a command line continuing through next lines and containing foo
+ this line continues the preciding one with other commands
+ this line continues the preciding one with other commands
this is a new command line
this is another command line

修改后的文字应该变成:

*this is a command line continuing through next lines and containing foo
*+ this line continues the preciding one with other commands
*+ this line continues the preciding one with other commands
this is a new command line
this is another command line

更简单的例子:

gas
foo
+ abc
+ def
+ ghi
bar
+ qwe
+ rty
baz
foo
bor

变成:

gas
*foo
*+ abc
*+ def
*+ ghi
bar
+ qwe
+ rty
baz
*foo
bor

【问题讨论】:

    标签: vim substitution


    【解决方案1】:

    您可以根据正则表达式模式选择行范围。有点

    :/foo/;/^[^+]/-1 s/^/\*
    

    这里我们选择从包含“foo”的行开始,直到(并排除)不以“plus”开头的行。然后简单地将“行首”替换为文字“星号”。

    当然,这是一个简化的例子,所以正则表达式有点脆弱。

    要重新执行上次执行的命令,您可以按 @: (然后按 @@ )。

    【讨论】:

      【解决方案2】:

      我创建了一个函数,它可以输出包含该模式的行,但保留已注释的行。它还检查行继续是否包含模式。

      function! Comment(pattern) abort
        let start_line = line('.')
        let s:foo = 0
      
        while search(a:pattern)
          if line('.') == start_line
            if s:foo
              break
            else
              let s:foo = 1
            endif
          endif
      
          if getline('.') =~ '^\*'
            continue
          endif
      
          let f = getline('.') =~ '^+'
          s/.*/\*&
          let l = line('.')
          let i = 0
      
      
          " " This commented block is for matching lines above pattern
          "
          " while getline(l-i) =~ '^+'
          "   normal! k
          "   s/.*/\*&
          "   let i += 1
          " endwhile
          "
          " if f
          "   normal! k
          "   s/.*/\*&
          " endif
          "
          " execute ':'.l
      
          let i = 1
          while getline(l+i) =~ '^+'
            normal! j
            s/.*/\*&
            let i += 1
          endwhile
      
        endwhile
      endfunction
      

      :call Comment("foo")的效果:

      BEFORE | AFTER
      -------|---------
      foo    |  *foo
      gas    |  gas
      foo    |  *foo
      + abc  |  *+ abc
      + def  |  *+ def
      + foo  |  *+ foo
      + ghi  |  *+ ghi
      bar    |  bar
      + qwe  |  + qwe
      + rty  |  + rty
      baz    |  baz
      fab    |  fab
      foo    |  *foo
      bor    |  bor
      hello  |  hello
      + foo  |  *+ foo
      abc    |  abc
      *foo   |  *foo
      *+ g   |  *+ g
      

      【讨论】:

      • 您好 Jorengarenar,非常感谢您的帮助。我尝试了它并且它有效,但我发现了几个问题。 1) 我想在我的模式中包含行首字符,以便它是 ^foo,但是这样做该函数不会修改任何内容。 2) 函数 cmets 也以 + 开头和前面的与模式匹配的行。但我只需要修改(评论)以下几行。我正在尝试自己修改它,但不知道我是否能够这样做。如果你有时间修复它......真的很感激!
      • @comaante 喜欢这个?
      • 是的,它对我帮助很大。有这两点需要解决。我正在努力……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      相关资源
      最近更新 更多