Vim:如何自动编号段落以及如何参考这个编号?

时间:2011-07-22 20:23:48

标签: vim

让我们说我有这个文本(段落用空行分隔 - 数字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:是否可以参考这些段落?例如,是否可以在the earlier question中将文本文件索引(由Prince Goulash和Herbert Sitz提供),但这次是使用段落编号而不是行号?

提前致谢

4 个答案:

答案 0 :(得分:2)

这是使用一对函数执行引号的一种方法:

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 :(得分:1)

问题一

这是一个枚举段落的功能。只需在文件中的任何位置: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

我没有彻底测试过这些功能,但它们似乎工作正常,至少在你的示例文本中是这样。让我知道你是如何上场的!

答案 2 :(得分:1)

这两个问题都可以比其他问题更容易解决。

为了解决以下两个编号段落的第一个问题 步骤充足。

  1. 缩进段落(在此处使用标签)。

    :v/^\s*$/s/^/\t/
    
  2. 插入段落编号(另请参阅my answerthe question on substitution with counter)。

    :let n=[0] | %s/^\s*\n\zs\ze\s*\S\|\%1l/\=map(n,'v:val+1')
    
  3. 创建索引的第二个问题需要一些脚本才能实现 由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,","))')
    

答案 3 :(得分:0)

我的方法是基于宏的:

  1. 以某种方式表示数字“ 0”并移至第一段的开头。

  2. 录制宏到

    1. 使用>}

      将该段落缩进
    2. 将存储的号码粘贴到正确的位置p

    3. 使用<ctrl>-a

      将数字递增1
    4. yiw粘贴粘贴的数字

    5. 使用}l/^\S

      移至下一段
  3. 根据需要多次执行宏以到达文档末尾。


粘贴数字,递增数字然后在宏内重新对其进行重载的方法是一项非常有用的技术,它在需要对事物进行编号时会派上用场。它非常简单,可以一次性使用。我主要将其用于地毯测井,但正如您的问题所示,它还有其他用途。