Vim Regex重复行分组

时间:2011-09-29 17:49:09

标签: regex sorting vim sed awk

我有一个这样的日志文件:

12 adsflljl
12 hgfahld
12 ash;al
13 a;jfda
13 asldfj
15 ;aljdf
16 a;dlfj
19 adads
19 adfasf
20 aaaadsf

我想把它们“分组”,就像这两个中的一个:

12 adsfllj, 12 hgfahld, 12 ash;al
13 a;jfda, 13 asldfj
15 ;aljdf
16 a;dlfj
19 adads, 19 adfasf
20 aaaadsf

12 adsfllj, hgfahld, ash;al
13 a;jfda, asldfj
15 ;aljdf
16 a;dlfj
19 adads, adfasf
20 aaaadsf

我完全陷入困境。如果vim没有这样做,我也有sed和awk以及bash。我只是不想写一个bash脚本,我想增加我的正则表达式

5 个答案:

答案 0 :(得分:6)

在Vim中你可以使用:

:%s/\(\(\d\+\) .*\)\n\2/\1, \2/g 

表示:如果在新行后匹配一组数字,请删除换行符并改为使用逗号。如果您不熟悉它们,则\1\2会反向引用。

不幸的是,这只会一次合并两次,所以在实现目标之前,你必须多次运行它。

编辑:一次性完成它的一种方法是循环并利用这样一个事实:一旦文件不再匹配,就会发出错误。虽然这个错误有点烦人,但是我用单行代码做得不好:

:while 1 | :%s/\(\(\d\+\) .*\)\n\2/\1, \2/g | :endwhile

答案 1 :(得分:5)

我只是使用awk:

awk '
  {
    sep = val[$1] ? ", " : ""
    val[$1] = val[$1] sep $2
  }
  END {for (v in val) print v, val[v]}
' log.file | sort > new.file

答案 2 :(得分:2)

在Vim中,我会使用命令

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

如果可以保证第一列始终包含数字ID。

否则,我会修改if-condition如下。

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

答案 3 :(得分:1)

另一种方法,这次使用宏(我建议你使用另一个解决方案,这个只是表明有很多方法可以做到这一点):

  

gg:%s/$/, 输入 qa0V? CTRL-R CTRL-W \>\&^ 输入 Jjq100@a:%s/.$// 返回

说明:

  • gg =>转到文件开头
  • :%s/$/, =>将逗号添加到每一行
  • qa =>开始将宏录制到寄存器a
  • 0V =>转到第一列,然后开始行选择
  • ? =>向后查找(你必须有set wrapscan
    • ctrl-r ctrl-w 在光标下插入单词。
    • \>确保结束
    • \&^确保在行首时匹配模式。您不能将^放在模式的开头,因为如果设置了incsearch,那么只要您键入^,然后 ctrl-r ctrl-w 将打印光标下的单词,该单词将移至上一行。
  • J会将视觉选择中的所有行与空格连接起来。
  • j将转到下一行
  • q将停止录制宏
  • 100@a将播放100次。
  • :%s/.$//将删除尾随逗号。

答案 4 :(得分:0)

我不认为在这里使用正则表达式是个好主意。您可以在@glenn中找到与vimscript编写的解决方案相同的想法如下:

function JoinLog()
    let d={}
    g/\v^\S+\s/let [ds, k, t; dl]=matchlist(getline('.'), '\v^(\S+)\s+(.*)') |
              \let d[k]=get(d, k, [])+[t]
    %delete _
    call setline(1, map(sort(keys(d)), 'v:val." ".join(d[v:val], ", ")'))
endfunction

您可以保留订单而不是排序:

function JoinLog()
    let d={}
    let ordered=[]
    g/\v^\S+\s/let [ds, k, t; dl]=matchlist(getline('.'), '\v^(\S+)\s+(.*)') |
              \if has_key(d, k) | let d[k]+=[t] |
              \else             | let ordered+=[k] | let d[k]=[t] |
              \endif
    %delete _
    call setline(1, map(copy(ordered), 'v:val." ".join(d[v:val], ", ")'))
endfunction