在Vim中,替换/搜索符号中是否存在“匹配的括号/括号/等”?

时间:2014-08-18 14:35:16

标签: regex vim

我想替换每次出现的“foo {...}”除了括号内的换行符(可能有空格,其他括号打开和关闭等),后面跟着“bar”。< / p>

例如,“foo {{}},bar”中的“foo {{}}”匹配但不匹配“foo {hello {}} bar”。

我已尝试/foo{.*}\(bar\)\@!/foo{.\{-}}\(bar\)\@!,但第一个匹配“foo {} bar {}”,第二个匹配“foo {{}} bar”(只有“foo” {{}“部分)。

3 个答案:

答案 0 :(得分:0)

这个正则表达式:

foo{.*}\([}]*bar\)\@!

匹配:

foo{{ }}
foo{{ }}, bar

但不是:

foo{hello{}}bar

答案 1 :(得分:0)

  

无法正确匹配任意级别的嵌套   括号使用正则表达式。但是,有可能   构建一个正则表达式来匹配支持有限数量的嵌套(I   认为这个答案没有尝试这样做)。 - 本

这确实......

最多一层内括号:

/foo{[^{}]*\({[^{}]*}[^{}]*\)*}\(bar\)\@!

最多两层内括号:

/foo{[^{}]*\({[^{}]*\({[^{}]*}[^{}]*\)*}[^{}]*\)*}\(bar\)\@!

最多三层内括号:

/foo{[^{}]*\({[^{}]*\({[^{}]*\({[^{}]*}[^{}]*\)*}[^{}]*\)*}[^{}]*\)*}\(bar\)\@!

...

答案 2 :(得分:0)

取决于您想要准确执行的替换,您也许可以使用宏来做到这一点。

例如:给定这段文字

line 1 -- -- -- -- array[a][b[1]]
line 2 -- array[c][d]
line 3 -- -- -- -- -- -- -- array[e[0]][f] + array[g[0]][h[0]]

array[A][B] 替换为 get(A, B)

这样做:

  • 将光标定位在文本的开头
  • /array<cr>
  • qq 开始录制宏
  • 独立于里面的内容改变数据(使用%去匹配括号,使用some register/mark/plugin删除括号周围)。例如 cwget(<esc>ldi[vhpa, <esc>ldi[vhpa)<esc>n -- 但宏通常是不可读的。
  • n 转到下一场比赛,q 停止录制
  • @q 重复使用(@@ 可以从第二次开始使用)

这可能不太方便,因为很容易出错(例如按I<home>A)并且您必须从头开始重做宏,但是它有效。

或者,您可以执行类似于 eregex.vim 插件的一些操作来扩展 vim 的正则表达式格式以支持这一点(因此您不必每次都重新键入庞大的正则表达式)。

概念证明:

"does not handle different magic levels
"does not handle '\/' or different characters for substitution ('s#a#b#')
"does not handle brackets inside strings


" usage: `:M/pattern, use \zm for matching block/replacement/flags`

command -range -nargs=* M :call SubstituteWithMatching(<q-args>, <line1>, <line2>)
":M/ inspired from eregex.vim

function SubstituteWithMatching(command, line1, line2)
    let EscapeRegex={pattern->escape(pattern, '[]\')}
    let openbracket ='([{'
    let closebracket=')]}'
    let nonbracketR='[^'.EscapeRegex(openbracket.closebracket).']'
    let nonbracketsR=nonbracketR.'*'


    let LiftLevel={pattern->
                \nonbracketsR
                \.'\%('
                \.'['.EscapeRegex(openbracket).']'
                \.pattern
                \.'['.EscapeRegex(closebracket).']'
                \.nonbracketsR
                \.'\)*'
                \}

    let matchingR=LiftLevel(LiftLevel(LiftLevel(nonbracketsR)))

    if v:false " optional test suite
        echo "return 0:"
        echo match('abc', '^'.matchingR.'$')
        echo match('abc(ab)de', '^'.matchingR.'$')
        echo match('abc(ab)d(e)f', '^'.matchingR.'$')
        echo match('abc(a[x]b)d(e)f', '^'.matchingR.'$')
        echo match('abc(a]b', '^'.matchingR.'$')
        "current flaw (not a problem if there's only one type of bracket, or if
        "the code is well-formed)

        echo "return -1:"
        echo match('abc(a(b', '^'.matchingR.'$')
        echo match('abc)a(b', '^'.matchingR.'$')
    endif

    let [pattern, replacement, flags]=split(a:command, "/")
    let pattern=substitute(pattern, '\\zm', EscapeRegex(matchingR), 'g')
    execute a:line1.','.a:line2.'s/'.pattern.'/'.replacement.'/'.flags
endfunction

此后,:'<,'>M/array\[\(\zm\)\]\[\(\zm\)\]/get(\1, \2)/g 可用于执行上述相同的任务(在视觉模式下选择文本后)