Как я занимаю место из списка строк в VIM?

Они - подсказки к компилятору для генерации префиксов подсказки на ответвлениях. На x86/x64 они поднимают один байт, таким образом, Вы получите самое большее однобайтовое увеличение для каждого ответвления. Что касается производительности, это полностью зависит от приложения - в большинстве случаев, предиктор ответвления на процессоре проигнорирует их в эти дни.

Редактирование: Забыл об одном месте, с которым они могут на самом деле действительно помочь. Это может позволить компилятору переупорядочивать график потока управления для сокращения количества ответвлений, взятых для 'вероятного' пути. Это может иметь отмеченное улучшение циклов, где Вы проверяете несколько случаев выхода.

5
задан Chuck 31 January 2015 в 00:44
поделиться

5 ответов

Я бы использовал функцию, у которой есть состояние, и вызову эту функцию из% s. Что-то вроде:

" untested code
function! InitRotateSubst()
    let s:rs_idx = 0
endfunction

function! RotateSubst(list)
    let res = a:list[s:rs_idx]
    let s:rs_idx += 1
    if s:rs_idx == len(a:list)
        let s:rs_idx = 0
    endif
    return res
endfunction

И используйте их с:

:call InitRotateSubst()
:%s/foo/\=RotateSubst(['bar', 'bar', 'baz', 'baz'])/

Вызов двух команд может быть инкапсулирован в одну команду, если вы хотите.


РЕДАКТИРОВАТЬ: Вот версия, интегрированная как команда, которая:

  • принимает столько замен, сколько мы желаем, все замены должны быть разделены символом-разделителем;
  • поддерживает обратные ссылки;
  • может заменять только N первых вхождений, N == количество замен, указанное, если команда call is banged (с символом!)
  • не поддерживает обычные флаги, такие как g, i (: h: s_flags ) - для этого мы должны, например, наложить командный вызов, чтобы он всегда завершался вверх с / (или любым другим символом-разделителем), если не последний текст интерпретируется как флаги.

Вот определение команды:

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

function! s:RotateSubstitute(bang, repl_arg) range
  let do_loop = a:bang != "!"
  " echom "do_loop=".do_loop." -> ".a:bang
  " reset internal state
  let s:rs_idx = 0
  " obtain the separator character
  let sep = a:repl_arg[0]
  " obtain all fields in the initial command
  let fields = split(a:repl_arg, sep)

  " prepare all the backreferences
  let replacements = fields[1:]
  let max_back_ref = 0
  for r in replacements
    let s = substitute(r, '.\{-}\(\\\d\+\)', '\1', 'g')
    " echo "s->".s
    let ls = split(s, '\\')
    for d in ls
      let br = matchstr(d, '\d\+')
      " echo '##'.(br+0).'##'.type(0) ." ~~ " . type(br+0)
      if !empty(br) && (0+br) > max_back_ref
    let max_back_ref = br
      endif
    endfor
  endfor
  " echo "max back-ref=".max_back_ref
  let sm = ''
  for i in range(0, max_back_ref)
    let sm .= ','. 'submatch('.i.')' 
    " call add(sm,)
  endfor

  " build the action to execute
  let action = '\=s:DoRotateSubst('.do_loop.',' . string(replacements) . sm .')'
  " prepare the :substitute command
  let args = [fields[0], action ]
  let cmd = a:firstline . ',' . a:lastline . 's' . sep . join(args, sep)
  " echom cmd
  " and run it
  exe cmd
endfunction

function! s:DoRotateSubst(do_loop, list, replaced, ...)
  " echom string(a:000)
  if ! a:do_loop && s:rs_idx == len(a:list)
    return a:replaced
  else
    let res0 = a:list[s:rs_idx]
    let s:rs_idx += 1
    if a:do_loop && s:rs_idx == len(a:list)
        let s:rs_idx = 0
    endif

    let res = ''
    while strlen(res0)
      let ml = matchlist(res0, '\(.\{-}\)\(\\\d\+\)\(.*\)')
      let res .= ml[1]
      let ref = eval(substitute(ml[2], '\\\(\d\+\)', 'a:\1', ''))
      let res .= ref
      let res0 = ml[3]
    endwhile

    return res
  endif
endfunction

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

:%RotateSubstitute#foo#bar#bar#baz#baz#

или даже, учитывая исходный текст:

AfooZ
BfooE
CfooR
DfooT

команда

%RotateSubstitute/\(.\)foo\(.\)/\2bar\1/\1bar\2/

выдаст:

ZbarA
BbarE
RbarC
DbarT
9
ответ дан 18 December 2019 в 13:15
поделиться

Это не совсем то, что вам нужно, но может быть полезно для циклов.

Я написал замену плагинов http://www.vim.org/scripts/script .php? script_id = 2294 , который, помимо прочего, может помочь с циклическим просмотром списков строк. Например,

 :Swaplist foobar foo bar baz

, затем введите

 This line is a foo

, создайте простую строку восстановления / вставки, перейдите к последнему слову и нажмите ctrl-a поменять местами.

 qqyyp$^A

затем выполните шаблон обмена

 100@q

, чтобы получить

This line is foo
This line is bar
This line is baz
This line is foo
This line is bar
This line is baz
This line is foo
This line is bar
This line is baz
This line is foo
This line is bar
This line is baz
...

Вероятно, он может быть применен к ваша проблема, хотя она {cword} чувствительна.

2
ответ дан 18 December 2019 в 13:15
поделиться

Вот как я бы попробовал этот макрос.

qa          Records macro in buffer a
/foo<CR>    Search for the next instance of 'foo'
3s          Change the next three characters
bar         To the word bar
<Esc>       Back to command mode.
n           Get the next instance of foo
.           Repeat last command
n           Get the next instance of foo
3s          Change next three letters
baz         To the word bar
<Esc>       Back to command mode.
.           Repeat last command
q           Stop recording.
1000@a      Do a many times.

Любые советы о том, как это лучше сделать, приветствуются.

спасибо, Мартин.

1
ответ дан 18 December 2019 в 13:15
поделиться

Вероятно, будет намного проще записать макрос, который может заменить первые два, а затем использовать: s для остальных.

Макрос может выглядеть как / foo ^ Mcwbar ^ [. Если вы не знакомы с режимом макросъемки, просто нажмите q , a (регистр для его сохранения), а затем нажмите / foo cwbar .

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

]
0
ответ дан 18 December 2019 в 13:15
поделиться

Почему бы и нет:

:%s/\(.\{-}\)foo\(\_.\{-}\)foo\(\_.\{-}\)foo\(\_.\{-}\)foo/\1bar\2bar\3baz\4baz/

Я не уверен, что он охватывает всю глубину проблемы, но действительно может служить простой заменой. Более сложное решение может покрыть решение, если это не поможет.

2
ответ дан 18 December 2019 в 13:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: