16

设想:

  • 我有一个包含管道(如| 字符)分隔数据的文本文件。
  • 管道分隔字段中的每个数据字段都可以是可变长度的,因此计数字符将不起作用(或使用某种子字符串函数......如果它甚至存在于 Vim 中)。

是否可以使用 Vim 删除整个文件从第二个管道到行尾的所有数据?大约有 150,000 行,因此手动执行此操作只会吸引受虐狂……

例如,更改以下行:

1111|random sized text 12345|more random data la la la|1111|abcde
2222|random sized text abcdefghijk|la la la la|2222|defgh
3333|random sized text|more random data|33333|ijklmnop

到:

1111|random sized text 12345
2222|random sized text abcdefghijk
3333|random sized text

我确信这可以以某种方式完成......我希望。

更新:我应该提到我在 Windows XP 上运行它,所以我无法访问一些提到的 *nix 命令(cut在 Windows 上无法识别)。

4

12 回答 12

31
:%s/^\v([^|]+\|[^|]+)\|.*$/\1/
于 2009-01-15T20:38:33.157 回答
18

您还可以录制宏:

qq02f|Djq

然后你就可以玩它100@q来在接下来的 100 行运行宏。

宏观解释:

  • qq:开始宏录制;
  • 0: 转到该行的第一个字符;
  • 2f|:查找该| 字符在该行中的第二次出现;
  • D: 删除当前位置到行尾的文本;
  • j: 转到下一行;
  • q: 结束宏录制。
于 2009-01-15T20:43:58.560 回答
8

如果您不必使用 Vim,另一种选择是 unixcut命令:

cut -d '|' -f 1-2 file > out.file
于 2009-01-15T20:43:02.213 回答
4

做同样事情的另一种 Vim 方法:

%s/^\(.\{-}|\)\{2}\zs.*//
%s/^\(.\{-}\zs|\)\{2}.*//  " If you want to remove the second pipe as well.

这一次,正则表达式匹配尽可能少的字符 ( \{-}),然后是 |两次 ( \{2}),它们被忽略以将所有后续文本 ( \zs) 替换为空 ( //)。

于 2009-01-15T22:31:52.010 回答
4

代替替换,可以使用该:normal命令在每一行上重复一系列两个普通模式命令:2f|,跳转到该| 行的第二个字符,然后D,删除所有内容直到行尾。

:%norm!2f|D
于 2011-09-30T04:47:00.173 回答
2

您可以使用:command用户命令来运行替换:

:command -range=% YourNameHere <line1>,<line2>s/^\v([^|]+\|[^|]+)\|.*$/\1/
于 2010-01-28T18:51:14.323 回答
1

你也可以这样做:

:%s/^\([^\|]\+|[^\|]\+\)\|.*$/\1/g
于 2009-01-15T20:48:21.657 回答
1

使用 awk:

awk -F"|" '{$0=$1"|"$2}1' file
于 2010-03-27T13:58:23.760 回答
0

我发现 vim 不擅长处理非常大的文件。我不确定你的文件有多大。也许 cat 和 sed 一起工作会更好。

于 2009-01-15T20:40:47.677 回答
0

这是一个 sed 解决方案:

sed -e 's/^\([^|]*|[^|]*\).*$/\1/'
于 2009-01-15T20:41:12.887 回答
0

为什么要使用 Vim?为什么不直接跑

cat my_pipe_file | cut -d'|' -f1-2
于 2009-01-15T20:42:57.453 回答
0

1,$这将通过 cut过滤缓冲区 ( ) 中的所有行来完成这项工作:

:1,$!cut -d '|' -f 1-2

要仅在当前行上执行此操作,请尝试:

:.!cut -d '|' -f 1-2
于 2009-01-15T21:02:19.677 回答