代码之家  ›  专栏  ›  技术社区  ›  Peter Stuifzand

在vim脚本中替换零宽度匹配

  •  3
  • Peter Stuifzand  · 技术社区  · 15 年前

    我编写了这个脚本,用一个空格替换光标周围的许多空格。但是,当我在光标周围没有空格的情况下使用它时,这不起作用。在我看来,VIM在零宽度的比赛中并没有被取代。

    function JustOneSpace()
        let save_cursor = getpos(".")
        let pos = searchpos(' \+', 'bc')
        s/\s*\%#\s*/ /e
        let save_cursor[2] = pos[1] + 1 
        call setpos('.', save_cursor)
    endfunction
    
    nmap <space> :call JustOneSpace()<cr>
    

    以下是几个例子(pipe | 光标):

    这条线

    hello     |      world
    

    变成

    hello |world
    

    但这条线

    hello wo|rld
    

    不会变成

    hello wo |rld
    

    更新: 通过将函数更改为以下值,它适用于上述示例。

    function JustOneSpace()
        let save_cursor = getpos(".")
        let pos = searchpos(' *', 'bc')
        s/\s*\%#\s*/ /e
        let save_cursor[2] = pos[1] + 1 
        call setpos('.', save_cursor)
    endfunction
    

    这条线

    你好,世界
    

    变成

    hello w|orld
    

    问题是光标移动到下一个字符。它应该在同一个地方。

    有什么建议和/或提示吗?

    4 回复  |  直到 15 年前
        1
  •  4
  •   DrAl    15 年前

    我认为你的脚本唯一的问题是位置保存看起来不正确。你基本上可以做你想做的事情:

    :s/\s*\%#\s*/ /e
    

    与问题中的(正确的)代码相同。您可以简单地将其映射为:

    :nmap <space> :s/\s*\%#\s*/ /e<CR>
    

    如果你想保存这个位置,它会变得更复杂一些。最好的办法可能是使用这样的工具:

    function! JustOneSpace()
        " Get the current contents of the current line
        let current_line = getline(".")
        " Get the current cursor position
        let cursor_position = getpos(".")
        " Generate a match using the column number of the current cursor position
        let matchRE = '\(\s*\)\%' . cursor_position[2] . 'c\s*'
        " Find the number of spaces that precede the cursor
        let isolate_preceding_spacesRE = '^.\{-}' . matchRE . '.*$'
        let preceding_spaces = substitute(current_line, isolate_preceding_spacesRE, '\1', "")
        " Modify the line by replacing with one space
        let modified_line = substitute(current_line, matchRE, " ", "")
        " Modify the cursor position to handle the change in string length
        let cursor_position[2] -= len(preceding_spaces) - 1
        " Set the line in the window
        call setline(".", modified_line)
        " Reset the cursor position
        call setpos(".", cursor_position)
    endfunction
    

    其中大部分是注释,但关键是要查看替换前后行的长度,并相应地决定新的光标位置。你可以通过比较你的方法来做到这一点 len(getline(".")) 之前和之后,如果你愿意的话。

    编辑

    如果希望光标在空格字符后结束,请修改行:

        let cursor_position[2] -= len(current_line) - len(modified_line)
    

    这样看起来像这样:

        let cursor_position[2] -= (len(current_line) - len(modified_line)) - 1
    

    编辑(2)

    我已经更改了上面的脚本来考虑您的注释,这样光标位置只会根据光标位置之前的空格数进行调整。这是通过创建第二个正则表达式来完成的,该表达式从行中提取光标前面的空格(而不是其他任何内容),然后根据空格数调整光标位置。

        2
  •  3
  •   Alan Moore Chris Ballance    15 年前

    我不使用vim,但是如果你想匹配零个或更多的空格,你不应该使用 ' *' 而不是 ' \+' ?

    编辑:是光标定位的问题:你现在要做的是在替换之前在空格的开头设置位置,然后向前移动一个位置,使其在空格之后。尝试将其设置为 结束 相反,像这样:

    search(' *', 'bce')
    

    这样,任何添加或删除都会发生 之前 光标位置。在大多数编辑器中,光标位置自动移动以跟踪这些更改。你不需要做任何getpos/setpos的事情。

        3
  •  0
  •   Community CDub    7 年前

    此函数基于 Al answer .

    function JustOneSpace()
        " Get the current contents of the current line
        let current_line = getline(".")
    
        " Get the current cursor position
        let cursor_position = getpos(".")
    
        " Generate a match using the column number of the current cursor position
        let matchre = '\s*\%' . cursor_position[2] . 'c\s*'
        let pos = match(current_line, matchre) + 2
    
        " Modify the line by replacing with one space
        let modified_line = substitute(current_line, matchre, " ", "")
    
        " Modify the cursor position to handle the change in string length
        let cursor_position[2] = pos
    
        " Set the line in the window
        call setline(".", modified_line)
        " Reset the cursor position
        call setpos(".", cursor_position)
    endfunction
    

    相反,我使用了法线和修改线之间的差异,找到了第一个与替换的正则表达式匹配的空间的位置。然后我将光标位置设置为+1。

        4
  •  0
  •   Reman    13 年前

    我使用的这个简单的方法几乎是相同的:

    nnoremap <leader>6 d/\S<CR>

    将光标放在要删除空格的位置,并删除光标和下一个文本后的所有空格。