Vim: Как автоматически нумеровать абзацы и как ссылаться на эту нумерацию? - PullRequest
8 голосов
/ 23 июля 2011

Допустим, у меня есть этот текст (абзацы разделены пустыми строками - номер 3 и 7 здесь):

This is my first paragraph line 1
This is my first paragraph line 2

This is my second paragraph line 4
This is my second paragraph line 5
This is my second paragraph line 6

This is my third paragraph line 8
This is my third paragraph line 9

Вопрос 1: Как я могу автоматически нумеровать эти абзацы (у меня получилось, но с неуклюжим макросом), чтобы получить такой результат:

1   This is my first paragraph line 1
    This is my first paragraph line 2

2   This is my second paragraph line 4
    This is my second paragraph line 5
    This is my second paragraph line 6

3   This is my third paragraph line 8
    This is my third paragraph line 9

Вопрос 2: Можно ли сослаться на эти абзацы? Например, возможно ли проиндексировать текстовый файл, как ответили (принц Гуляш и Герберт Ситц) в предыдущем вопросе , но на этот раз с номерами абзацев, а не с номерами строк?

Заранее спасибо

Ответы [ 3 ]

2 голосов
/ 23 июля 2011

Вот один из способов сделать номера ссылок с помощью пары функций:

function! MakeRefMarkers()
     " remove spaces from empty lines
     %s/^ \+$//
     " mark all spots for ref number
     %s/^\_$\_.\zs\(\s\|\S\)/_parref_/
     "initialize ref val
     let s:i = 0
     " replace with ref nums
     %s/^_parref_/\=GetRef()/
endfunction

function! GetRef()
     let s:i += 1
     return s:i . '.  '
endfunction

Затем просто сделайте это, вызвав MakeRefMarkers ().Он не удаляет существующие номера ссылок, если они там есть, это потребует еще одного шага.И он не улавливает первый абзац, если это первая строка в файле (то есть без предшествующей пустой строки).Но он обрабатывает ситуации, когда между абзацами более одной пустой строки.

1 голос
/ 23 июля 2011

Обе проблемы могут быть решены намного проще, чем это предлагают другие.

Чтобы решить первую проблему нумерации абзацев, следующие два шаги достаточно.

  1. Отступ абзацев (здесь используются вкладки).

    :v/^\s*$/s/^/\t/
    
  2. Вставьте нумерацию абзаца (см. Также мой ответ на вопрос при замене со счетчиком ).

    :let n=[0] | %s/^\s*\n\zs\ze\s*\S\|\%1l/\=map(n,'v:val+1')
    

Вторая проблема создания индекса требует некоторых сценариев, чтобы решается только средствами Vim. Ниже приведен список небольшой функции, WordParIndex(), который должен запускаться после нумерации абзацев согласно описанию первой проблемы.

function! WordParIndex()
    let [p, fq] = [0, {}]
    let [i, n] = [1, line('$')]
    while i <= n
        let l = getline(i)
        if l !~ '^\s*$'
            let [p; ws] = ([p] + split(l, '\s\+'))[l=~'^\S':]
            for w in ws
                let t = get(fq, w, [p])
                let fq[w] = t[-1] != p ? t + [p] : t
            endfor
        endif
        let i += 1
    endwhile
    return fq
endfunction

Возвращаемым значением функции WordParIndex() является целевой индекс толковый словарь. Чтобы добавить его текстовое представление внизу буфера, запустите

:call map(WordParIndex(), 'append(line("$"),v:key.": ".join(v:val,","))')
1 голос
/ 23 июля 2011

Вопрос первый

Вот функция для перечисления абзацев. Просто сделайте :call EnumeratePara() в любом месте вашего файла. Переменная indent может быть изменена по вашему желанию. Дайте мне знать, если что-то нужно исправить или объяснить.

function! EnumeratePara()
    let indent=5
    let lnum=1
    let para=1
    let next_is_new_para=1
    while lnum <= line("$")
        let this = getline(lnum)
        if this =~ "^ *$"
            let next_is_new_para=1
        elseif next_is_new_para==1 && this !~ "^ *$"
            call cursor(lnum,1)
            sil exe "normal i" . para . repeat(" ",indent-len(para))
            let para+=1
            let next_is_new_para=0
        else
            call cursor(lnum,1)
            sil exe "normal i" . repeat(" ",indent)
        endif
        let lnum+=1
    endwhile
endfunction

Вопрос второй

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

function! MapLinesToParagraphs()
    let lnum=1
    let para_lines=[]
    let next_is_new_para=1
    let current_para=0
    while lnum <= line("$")
        let this = getline(lnum)
        if this =~ "^ *$"
            let next_is_new_para=1
        elseif next_is_new_para==1
            let current_para+=1
            let next_is_new_para=0
        endif
        call add(para_lines,current_para)
        let lnum+=1
    endwhile
    return para_lines
endfunction

Так что para_lines [i] даст абзац строки i.

Теперь мы можем использовать существующую функцию IndexByWord () и использовать MapLinesToParagraph () для преобразования номеров строк в номера абзацев, прежде чем мы их вернем:

function! IndexByParagraph( wordlist )
    let temp_dict = {}
    let para_lines = MapLinesToParagraphs()
    for word in a:wordlist
        redir => result
        sil! exe ':g/' . word . '/#'
        redir END
        let tmp_list = split(strtrans(result),"\\^\@ *")
        let res_list = []
        call map(tmp_list, 'add(res_list,str2nr(matchstr(v:val,"^[0-9]*")))')
        call map(res_list, 'para_lines[v:val]')
        let temp_dict[word]  = res_list
    endfor
    let result_list = []
    for key in sort(keys(temp_dict))
        call add(result_list, key . ' : ' . string(temp_dict[key])[1:-2])
    endfor
    return join(result_list, "\n")
endfunction

Я не очень тщательно тестировал эти функции, но, похоже, они работают нормально, по крайней мере, в вашем примере текста. Дайте мне знать, как вы поживаете!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...