是否可以执行同时查找和替换的方法?

例如:我想将所有1替换为0,同时将所有0替换为1

[
    [1, 1, 1, 1, 1, 0],
    [1, 1, 1, 1, 0, 1],
    [1, 1, 1, 0, 1, 1],
    [1, 1, 0, 1, 1, 1],
    [1, 0, 1, 1, 1, 1],
    [0, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 0],
]



#1 楼

是的,您可以通过使用表达式来实现。对于这种特殊情况,您可以使用Vim算术并计算1-x,它将把0变成1,将1变成0。

:s/\d/\=1-submatch(0)/g


对于更一般的替换情况,您可以可以使用Dict存储匹配到替换字符串的映射。

例如,将数字转换为书面数字:

:let repl = {"0": "zero", "1": "one"}
:s/\d/\=repl[submatch(0)]/g


请参阅:


:help sub-replace-expression
:help /\d
:help submatch()
:help Dict


#2 楼

这里已经有很多很好的答案,但是为了完整起见,我觉得我应该指出,在大多数实际情况下,如果将多个ex命令与条形码字符|连接起来,它们的作用就像一个操作。 />
特别地,它们将导致每个撤消树和更改列表中的单个项。 1:

:%s/1/TEMP/g | %s/0/1/g | %s/TEMP/0/g


评论


我喜欢这种解决方案;另一种则更聪明,并且可以说是更好的,但是这一点更容易记住并且认知负荷较低。有时候,我花费更多的时间使“聪明”的方法生效,而不是仅仅使用“愚蠢”的方法所节省的时间。也许我不够聪明,呵呵

–马丁·图尔诺伊(Martin Tournoij)
20年4月30日在18:15

#3 楼

在您的特定用例中,我认为您可以在网上方便地进行操作:

#4 楼

确定:

%s/[01]/\="10"[submatch(0)]/g


匹配01并用

"10"[0] = 1


"10"[1] = 0

#5 楼

这个答案比其他答案更长,它没有利用特定的数据值优势,这是用n个不同的替换项替换n个不同的值的通用解决方案:

let d={0:1,1:0} | %s/\v(0|1)/\=d[submatch(0)]/g | unlet d
如果您想一次更换将Hello vim 8更改为Oh god 9

let d={'Hello':'Oh','vim':'god',8:9} | %s/\v(Hello|vim|8)/\=d[submatch(0)]/g | unlet d


#6 楼

我真的很惊讶,vi / vim中没有本机tr,但是如果您的平台足够UNIXy,那么就有一个用于此的外部命令:

我个人会用的东西,但可能不够便携。

评论


有:h tr()

–克里斯蒂安·布拉班特(Christian Brabandt)
20-04-30在20:24

从函数中,我们可以定义一个命令:请参见stackoverflow.com/a/25665554/15934

–卢克·赫米特(Luc Hermitte)
20-04-30在22:37

#7 楼

我很确定我已经在vi.SE或stackoverflow上对一般情况给出了答案,但是找不到Q / A ...提供以下命令可以在您的情况下使用的命令CycleSubstitute

:[range]CycleSubstitute/0/1


我已经将其打包在这里。它是通过以下方式实现的:

:command! -bang -nargs=1 -range CycleSubstitute <line1>,<line2>call s:CycleSubstitute("<bang>", <f-args>)

function! s:CycleSubstitute(bang, repl_arg) range
  let do_loop = a:bang != "!"
  let sep = a:repl_arg[0]
  let fields = split(a:repl_arg, sep)
  let cleansed_fields = map(copy(fields), 'substitute(v:val, "\\[<>]", "", "g")')
  " build the action to execute
  let action = '\=s:DoCycleSubst('.do_loop.',' . string(cleansed_fields) . ', "^".submatch(0)."$")'
  " prepare the :substitute command
  let args = [join(fields, '\|'), action ]
  let cmd = a:firstline . ',' . a:lastline . 's'
        \. sep . join(fields, '\|')
        \. sep . action
        \. sep . 'g'
  " echom cmd
  " and run it
  exe cmd
endfunction

function! s:DoCycleSubst(do_loop, fields, what)
  let idx = (match(a:fields, a:what) + 1) % len(a:fields)
  return a:fields[idx]
endfunction


#8 楼

类似于@LucHermitte的答案,SwapStrings插件使您可以执行

:%SwapStrings 0 1


我自己的PatternsOnText插件提供了:SubstituteMultiple命令(除其他外),该命令可以作为特例进行交换原子进行多次替换(即不引入临时替换)的方法:

:%SubstituteMultiple /0/1/ /1/0/ g


#9 楼

要添加到允许这样做的插件列表中,vim-abolish具有Subvert函数,可以利用它来实现多次替换:

%Subvert/{1,0}/{0,1}/g


#10 楼

:%s/\([01]\)/\=1-submatch(1)/g


替换命令中发生以下情况


搜索1或0,将其记住为子匹配项1(在第一个/和第二个/之间)
通过从1(第二个和第三个/之间)减去值来替换值。
1变为0,0变为1
<=替换部分中的表达式

评论


欢迎来到Vi和Vim!好的答案通常会在代码旁边提供解释,以便提供指导

– D. Ben Knoble♦
20年5月1日下午1:29