在VIM中自动将文件拆分为多个文件?

时间:2017-09-05 14:51:36

标签: vim

我是VIM的新手,我尝试将文件拆分为多个文件。这是一个测试文件:

Something1;XXXword;blabla(about 500 signs);
Something1;XXXword;(about 500 signs);
Something1;YYYword;(about 500 signs);
Something1;RRRword;(about 500 signs);

XXX可能是2到20个字符的单词。当下面的单词(XXX / YYY / RRR)发生变化之前,#34; Something1"应该是一个剪切,以下行直到XXX更改应该是另一个新文件,依此类推。

应该如此:

File1:
Something1;XXXword;blabla(about 500 signs);Something1;XXXword;(about 500 signs);

File2:
Something1;YYYword;(about 500 signs);

File3:
Something1;RRRword;(about 500 signs)

有没有办法像专业人士那样做?谢谢:))

2 个答案:

答案 0 :(得分:6)

我会推荐一种不同的工具,比如Awk。

awk -F';' '{printf "%s", $0 >> $2}' your_file.txt

这会将每一行拆分为由;分隔的列。每行将附加(>>)到以第二列$2命名的文件(例如XXXword)。将新行($0除外)的整行printf "%s"附加/打印到新文件中,以便所有内容都是一行。

注意:我使用gawk作为awk实施,您可能需要根据awk实施情况进行调整。

对于更复杂的情况

在以下情况下,您有XXXYYYXXX

Something1;XXXword;blabla(about 500 signs);
Something1;YYYword;(about 500 signs);
Something1;XXXword;(about 500 signs);

如果这应该产生3个文件(1 YYY个文件和2个XXX个文件),那么我们也可以使用Awk:

awk -F';' 'last != $2 {f[$2]++} {printf "%s", $0 >> $2 f[$2]; last = $2}' your_file.txt

这将生成文件:XXXword1XXXword2YYYword1

这类似于上面的awk示例,除了我们使用字典/数组来存储第二列从前一行f[$2]++更改last != $2 {...}的次数。确保在打印每一行后将last设置为第二列。将行$0输出到以$2 f[$2]命名的文件(相邻变量和字符串将被连接)。

答案 1 :(得分:1)

您必须按照其他任何语言对其进行编程进行编程。我的第一反应就是Perl BTW。

function! s:split(root) abort
  " todo: check empty buffers
  let lines = getline(1, '$')
  let nb_lines = len(lines)
  let files = []

  let crt = 0
  while crt < nb_lines
    " I suppose the word is the second field in a .csv file
    let word = matchstr(lines[crt], '^[^;]*;\zs[^;]*\ze;')
    " This is where the real magic happens, see :h /\@!
    let next = match(lines, '^[^;]*;\(\('.word.'\)\@![^;]\)*;', crt)
    if next == -1 | let next = nb_lines | endif
    let files += [ lines[crt : (next-1)] ]
    let crt = next
  endwhile

  echo files
endfunction

command! -nargs=1 SplitBuffer :call s:split("<args>")

而不是let files += [ something ],您需要执行

:let index = 0
...
:for...
    ...
    :call writefile(a:root.index, lines[crt : (next-1)])
    :let index += 1
:endfor

编辑:

如果序列XXXYYYXXX将导致两个文件而不是3个,则可以使用此(复杂且未经测试的)oneliner完成 - 仍然,更喜欢@Peter Rincker基于awk的解决方案。

:call map(getline(1, '$'), 'writefile(v:val, split(v:val, ";")[1], "a")')