簡體   English   中英

在 Vim 中,替換/搜索符號中是否有“匹配大括號/括號/等”等價物?

[英]In Vim, is there a “matching braces/parenthesis/etc” equivalent in substitute/search symbols?

例如,我想用括號內的換行符(可能有空格、其他括號打開和關閉等)以外的任何內容替換“foo{...}”的每次出現,而不是后跟“bar”。

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

我試過/foo{.*}\\(bar\\)\\@! /foo{.\\{-}}\\(bar\\)\\@! 但第一個將匹配“foo{}bar{}”,第二個將匹配“foo{{}}bar”(僅“foo{{}”部分)。

這個正則表達式:

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

火柴:

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

但不是:

foo{hello{}}bar

使用正則表達式不可能正確匹配任意級別的嵌套括號。 但是,可以構建一個正則表達式來匹配支持有限數量的嵌套(我認為這個答案沒有嘗試這樣做)。 – 本

這確實...

最多一層內大括號:

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

最多兩層內大括號:

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

最多三個級別的內括號:

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

...

取決於您想要准確執行的替換,您可能可以使用宏來做到這一點。

例如:鑒於此文本

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

get(A, B)替換array[A][B]

要做到這一點:

  • 將光標定位在文本的開頭
  • /array<cr>
  • qq開始錄制宏
  • 做一些事情來改變與里面內容無關的數據(使用%轉到匹配的括號,並使用一些 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可以用來做同樣的事情上面的任務(在視覺模式下選擇文本后)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM