Подберите блок в скобках, используя регулярные выражения в vim - PullRequest
9 голосов
/ 28 февраля 2011

Я пытаюсь сопоставить содержимое, которое принадлежит определенному ( и его совпадению ), как обнаружено vim при использовании движения %.

В частности, я ищу регулярное выражение, которое выглядит как гипотетический /someKeyword (\{pair}\(.*\))\{pair}/, если бы существовали такие модификаторы, как \{pair}, который при применении к двум точно двум символам в регулярном выражении делает второй совпадение только в том случае, если это совпадающая скобка с первой (% -wise).

Шаблон, который я ищу, должен соответствовать внутреннему содержимому первой скобки, следующей за someKeyword (примечание, код, с которым он должен работать, всегда корректно заключен в квадратные скобки), как в примерах:

Для someKeyword ("aaa") субматч будет соответствовать "aaa". Аналогично someKeyword ("aaa)") будет соответствовать "aaa)", а someKeyword(("double-nested stuff")) будет соответствовать ("double-nested stuff")

Но также в таких случаях, как:

(
  someKeyword("xyz"))

где оно должно совпадать "xyz".

Есть ли какой-нибудь способ использовать функцию сопоставления скобок vim в регулярных выражениях? А если нет, какое другое решение может работать для достижения этой цели?

Редактировать 1: сопоставляемое содержимое может занимать несколько строк.

Ответы [ 4 ]

5 голосов
/ 28 февраля 2011

Это невозможно с регулярными выражениями vim (поскольку язык, допускающий такие вложенные конструкции, не является регулярным), но возможно с «регулярными» выражениями, предоставляемыми perl (а также с другими языками, которых я не знаю достаточно, чтобы быть уверенным) и perl можно использовать изнутри vim.Мне не нравятся привязки vim-perl (потому что они очень ограничены), но если вы знаете все случаи, которые должны работать, то вы можете использовать функцию рекурсии регулярных выражений perl (требуется более новый perl, у меня есть 5.12 *):

perl VIM::Msg($+{"outer"}) if $curbuf->Get(3) =~ /someKeyword\((?'outer'(?'inner'"(?:\\.|[^"])*"|'(?:[^']|'')*'|[^()]*|\((?P>inner)*\))*)\)/

Обратите внимание, что если вы можете избежать таких регулярных выражений, вы должны это сделать (поскольку вы слишком сильно зависите от re-compiler), поэтому я предлагаю использовать движения vim напрямую:

let s:reply=""
function! SetReplyToKeywordArgs(...)
    let [sline, scol]=getpos("'[")[1:2]
    let [eline, ecol]=getpos("']")[1:2]
    let lchar=len(matchstr(getline(eline), '\%'.ecol.'c.'))
    if lchar>1
        let ecol+=lchar-1
    endif
    let text=[]
    let ellcol=col([eline, '$'])
    let slinestr=getline(sline)
    if sline==eline
        if ecol>=ellcol
            call extend(text, [slinestr[(scol-1):], ""])
        else
            call add(text, slinestr[(scol-1):(ecol-1)])
        endif
    else
        call add(text, slinestr[(scol-1):])
        let elinestr=getline(eline)
        if (eline-sline)>1
            call extend(text, getline(sline+1, eline-1))
        endif
        if ecol<ellcol
            call add(text, elinestr[:(ecol-1)])
        else
            call extend(text, [elinestr, ""])
        endif
    endif
    let s:reply=join(text, "\n")
endfunction
function! GetKeywordArgs()
    let winview=winsaveview()
    keepjumps call search('someKeyword', 'e')
    setlocal operatorfunc=SetReplyToKeywordArgs
    keepjumps normal! f(g@i(
    call winrestview(winview)
    return s:reply
endfunction

Выможет использовать что-то вроде

let savedureg=@"
let saved0reg=@0
keepjumps normal! f(yi(
let s:reply=@"
let @"=savedureg
let @0=saved0reg

вместо operatorfunc для сохранения и восстановления регистров, но приведенный выше код оставляет все регистры и пометки нетронутыми, что я не могу гарантировать с сохраненными * данными.Это также гарантирует, что если вы удалите join() вокруг text, вы сохраните информацию о расположении NULL (если вы, конечно, заботитесь о них).Это невозможно с вариантом регистров.

3 голосов
/ 28 февраля 2011

Большинство диалектов регулярных выражений не могут этого сделать. Это возможно с реализацией .NET (см. здесь ), но очень, очень уродливо и не должно использоваться по моему мнению.

1 голос
/ 28 февраля 2011

Вы можете сделать это довольно легко с помощью макроса.Вы будете искать ключевое слово с помощью регулярного выражения, а затем искать начало текста, затем его конец, а затем вы можете предпринять любое действие, которое вам нужно.

Например, чтобы восстановить нужный текст:

qa/somekeyword\s*
/(
lvh%hyq

Теперь всякий раз, когда вы используете макрос с @a, вы хотите получить следующий интересующий вас бит текста.

1 голос
/ 28 февраля 2011

Как сказал Йенс, этого нельзя сделать с помощью регулярных выражений Vim.

Однако, если вы хотите выполнить специальную обработку, вы можете сделать следующее:

  • Найдите открывающие скобки, которые вас интересуют, а затем запустите макрос, который вставит некоторый символ (скажем, ^@) после открывающей скобки и перед закрывающей скобкой, используя привязку %.
  • Затем измените регулярное выражение соответственно.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...