Easiest way to swap occurrences of two strings in Vim?

*爱你&永不变心* 提交于 2019-11-27 17:59:20

I'd do it like this:

:%s/\v(foo|bar)/\={'foo':'bar','bar':'foo'}[submatch(0)]/g

But that's too much typing, so I'd do this:

function! Mirror(dict)
    for [key, value] in items(a:dict)
        let a:dict[value] = key
    endfor
    return a:dict
endfunction

function! S(number)
    return submatch(a:number)
endfunction

:%s/\v(foo|bar)/\=Mirror({'foo':'bar'})[S(0)]/g

But that still requires typing foo and bar twice, so I'd do something like this:

function! SwapWords(dict, ...)
    let words = keys(a:dict) + values(a:dict)
    let words = map(words, 'escape(v:val, "|")')
    if(a:0 == 1)
        let delimiter = a:1
    else
        let delimiter = '/'
    endif
    let pattern = '\v(' . join(words, '|') . ')'
    exe '%s' . delimiter . pattern . delimiter
        \ . '\=' . string(Mirror(a:dict)) . '[S(0)]'
        \ . delimiter . 'g'
endfunction

:call SwapWords({'foo':'bar'})

If one of your words contains a /, you have to pass in a delimiter which you know none of your words contains, .e.g

:call SwapWords({'foo/bar':'foo/baz'}, '@')

This also has the benefit of being able to swap multiple pairs of words at once.

:call SwapWords({'foo':'bar', 'baz':'quux'})

You can do this easily with Tim Pope's Abolish plugin

:%S/{transmit,receive}/{receive,transmit}

Here is how I swap two words skip & limit.

%s/skip/xxxxx/g|%s/limit/skip/g|%s/xxxxx/limit/g

Pretty sure someone could turn it into a shorter command which accepts two arguments.

The swapstrings plugin provides a handy command for this:

:SwapStrings string_a string_b

You can do it with a single command as shown in my code below:

:%s/\<\(string_a\|string_b\)\>/\=strpart("string_bstring_a", 8 * ("string_b" == submatch(0)), 8)/g

Update: the editor here in stackoverflow is driving me crazy, because it keeps removing backslahes...

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!