Замените самый первый соответствующий шаблон на более поздние строки в Vim

У меня есть длинный текст, в котором некоторые строки нужно повторить позже.

В тексте ставлю такие теги:

{F1}text need to be repeated later{/F1}

поэтому я могу добавить несколько {F1}{/F1} в более поздние разделы и поместить содержимое первой строки между ними.

Проблема в том, что будет много таких тегов, как {F2}{/F2} и т. д., и этот шаблон соответствует всем им:

{\(.*\)}.*{\/\1}

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

Как я мог это сделать? Я принимаю любое решение, не обязательно используя мою идею пометить первые строки тегами {}{/}. Тегов будет много, и я не хочу делать это один за другим с отдельными командами-заменителями.

Я пробовал с этим:

:g/{\(.*\)}\(.*\){\/\1}/s/{\1}.*{\/\1}/{\1}\2{\/\1}/

но он говорит:

E65 Illegal back reference.

person kissgyorgy    schedule 11.09.2011    source источник
comment
не могли бы вы опубликовать пример текста (до/после), чтобы мы могли лучше понять, что именно вы хотите сделать?   -  person Benoit    schedule 11.09.2011
comment
Я могу ошибаться, но я думаю, что ошибка возникает из-за использования обратных ссылок в замещающей части s/// без захвата в части совпадения.   -  person johnny    schedule 11.09.2011


Ответы (1)


Функция ReplicateTags(), указанная ниже, запускает команду замены, заменяя содержимое каждого тега (в соответствии с его описанием в вопросе) текстом в первом вхождении этого тега. Подстановка работает со всем буфером и обрабатывает все теги за один проход (принимая многострочные неперекрывающиеся теги). Функция возвращает словарь, который сопоставляет имена тегов с содержимым их первого появления.

function! ReplicateTags()
    let dict = {}
    %s/{\([^}]\+\)}\(\_.\{-}\){\/\1}/\=Tag(dict, submatch(1), submatch(2))/ge
    return dict
endfunction

function! Tag(dict, tag, str)
    let a:dict[a:tag] = get(a:dict, a:tag, a:str)
    return printf('{%s}%s{/%s}', a:tag, a:dict[a:tag], a:tag)
endfunction
person ib.    schedule 11.09.2011
comment
Мужик, это потрясающе! :D Именно то, что я хотел. - person kissgyorgy; 12.09.2011