如何使用:g命令才能满足要求?

时间:2013-12-15 09:26:35

标签: regex vim

有一个这样的日志文件:

adsflljl    abc
hgfahld abc
ash;al  abc
a;jfda  cd
asldfj  cd
;aljdf  de
a;dlfj  dh
adads   ae
adfasf  ae
aaaads  hi

我想像这样“分组”他们:

adsflljl,hgfahld,ash;al abc
a;jfda,asldfj   cd
;aljdf  de
a;dlfj  dh
adads,adfasf    ae
aaaads  hi

我的方法是使用%s/^\v(.*)\t(.*)\n(.*)\t\2/\1,\3\t\2

我知道使用更换几次,我可以达到上述要求。

但是 Vim Regex Duplicate Lines Grouping

用户ib的方式是

:g/^\S\+/y|if matchstr(@",@/)==matchstr(getline(line('.')-1),@/)|s//,/|-j!

我把它改成了

:g/\t\S\+$/y|if matchstr(@",@/)==matchstr(getline(line('.')+1),@/)|s//,/|j!

但它不起作用。为什么?如何使用:g命令才能达到上述要求?

3 个答案:

答案 0 :(得分:1)

你并没有完全理解原来的:g命令,只是搞砸了它(虽然你的努力非常接近)。那很危险;不幸的是,要成为Vim大师,你必须花时间剖析每个子命令。只有这样,您才能获得使其适合您的情况的理解。

差异

  • 原始分组在第一个列(regexp:^\S\+);你在最后一个上进行分组。 y ank命令包含尾随换行符,因此以下matchstr()比较将失败。只需用norm! y$
  • 拉出线条的文字(没有换行)
  • 您没有加入以上行,而是以下行;但这会混淆:g次迭代。相反,请保持方向,只需将替换应用于上述行:-s//,/,然后加入当前行。

结果

此命令产生所需的结果:

:g/\t\S\+$/exe 'norm! y$'|if matchstr(@",@/)==matchstr(getline(line('.')-1),@/)|-s//,/|j!|endif

答案 1 :(得分:0)

如果你不介意错误信息,这将有效:

while 1 | %s;\v^(\S+)(\s+)(\S+)\_s*(\S+)\s+\3;\1,\4\2\3;g | endwhile

这一直在重复,直到没有更多的匹配(错误)。

答案 2 :(得分:0)

您可以使用或其他任何语言执行脚本编写。在我看来,使用它开发大型脚本并不容易,但它对于像这样的情况很有用。但这很有趣,你会学到不同的东西。这里有脚本:

"" List with the unique keys (second field)
let l = []

"" Dictionary which its values will be a list with all first fields common 
"" to their keys.
let d = {}

"" Traverse the whole file line by line, split it with spaces and fill either 
"" the list and the dict.
for line in range(1, line('$'))
    let fields = split(getline(line))
    if ! has_key(d, fields[1])
        let d[fields[1]] = []
    endif
    call add(d[fields[1]], fields[0])
    if empty(l) || l[-1] != fields[1]
        call add(l, fields[1])
    endif
endfor

"" Delete the buffer content.
1,$delete

"" The list keep the keys ordered as in the original file. Get each one 
"" and extract for the dictionary the list of values and print them joined 
"" with commas.
for key in l
    let delem = d[key]
    call append(line('$') - 1, join(delem, ',') . ' ' . key)
endfor

"" Delete a traling newline from last line.
delete

"" Save and quit
wq

像以下一样运行:

vim -u NONE -N -S script.vim infile

请注意,我避免使用-u NONE加载特殊配置值。此前的代码也保存在script.vim中。文件已就地修改,结果为:

adsflljl,hgfahld,ash;al abc 
a;jfda,asldfj cd
;aljdf de
a;dlfj dh
adads,adfasf ae
aaaads hi