如何在VIM中替换行尾符

8

如何替换大文件(>100MB)中的所有行尾符?

我尝试过执行以下命令:

:%s/\n/, /g

但速度太慢了。


为什么你想在VIM中这样做呢?你最终只会得到一行很长的代码,而且你无法阅读(用眼睛看的话)。此外,有哪些行尾存在:DOS、UNIX、MAC或它们的组合? - Marichyasana
6个回答

8

所以,我经过测试和计时一些其他人给出的答案,还有自己的一个Python答案。这是我的结果:

> time tr "\n" "," < lines > line
real    0m1.617s
user    0m0.100s
sys     0m1.520s

python:

> time python -c 'import sys; print sys.stdin.read().replace("\n",", "),' < lines > line
real    0m1.663s
user    0m0.060s
sys     0m1.610s

awk:

> time awk '{printf("%s, ", $0)}' lines > line                                 
real    0m1.998s
user    0m0.390s
sys     0m1.600s

perl:

> time perl -e 'while (<>) { chomp; print "$_, " }' lines > line
real    0m2.100s
user    0m0.590s
sys     0m1.510s

sed:

> time sed 's/$/, /g' lines > line                                             
real    0m6.673s
user    0m5.050s
sys     0m1.630s

这是我使用的文件:
> ls -lh lines
-rw-r--r-- 1 some one 101M 2010-03-04 19:54 lines
> wc -l < lines
1300000
> head -n 3 < lines
The pretty pink puma pounced on the unsuspecting aardvark, the scientist watched.
The pretty pink puma pounced on the unsuspecting aardvark, the scientist watched.
The pretty pink puma pounced on the unsuspecting aardvark, the scientist watched.
> head -n 1 < lines | wc -c
82

最初的时间是在cygwin中记录的,现在已经使用完全更新的ubuntu 9.10进行了记录。此外,文本文件大小增加到100兆字节,并且每行大约有80个字符。可以看出,除了sed之外,几乎任何其他东西都是一个好主意。


2
我非常怀疑你的 awk 结果。执行命令时应该多次测试,而不仅仅是一次。考虑到导入模块和其他东西需要时间,Python 不应该比 awk 更快。 - ghostdog74
它被运行了几次,那大概是平均水平。我只是又运行了大约10次,每次1.7xx。如果我不使用cygwin awk,也许会有所不同。 - Seamus Connor
你说的没错,我怀疑我的awk结果,我在一台真正的Linux机器上重新运行了它,速度快多了。 - Seamus Connor

3

:%s/$/, / 后跟 :1,$j 可能更快。否则,可以使用外部实用程序进行操作:

perl -e 'while (<>) { chomp; print "$_, " }' input_file > output_file

awk '{printf("%s, ", $0)}' input_file > output_file

我不知道哪个最快。

在头脑中没有想到最快的方法。

perl -ne 'chomp; print "$_, "' file-n "假设while循环"。 - ghostdog74
@sparrkey,“perl会运行得更快”这种说法是没有依据的。 - ghostdog74
@ghostdog74 你说得对,它确实不是。事实上,它相当可比。Python和tr也是如此。 - Seamus Connor

2
使用这个Perl脚本来遍历你的文件; 这比在VIM中将所有内容存储在内存中更快。只需将输出导入新文件即可。
#!/usr/local/bin/perl

while (<>) {
  $_ =~ s/\n/,/g;
  print $_;
}

我猜测Perl解释器可能不够聪明,无法知道在这种情况下$_除了最后一个字符外不能有换行符 - chomp可能会更快。 - Cascabel
在我的完全不科学的测试中,使用chomp处理一个100兆文件大约比不使用快300毫秒。 - Seamus Connor

1

你必须在vim中完成这个吗?

有一个很好的Unix实用程序可以进行基于字符的转换。它叫做tr。 一些参考资料

在你的情况下,应该是这样的:

tr "\n" "," < input_file > output_file

这几乎肯定比我发布的解决方案更快,但不幸的是,它用“,”代替了OP请求的“, ”。我不确定是否有一种方法可以使用tr来实现这一点,有吗? - Cascabel
tr 命令只接受单个字符。 - ghostdog74
不,没有,我没有注意到那里有空格。要输入多个字符,可以使用下面某人发布的sed命令。 - pajton
是的,但是sed真的不是一个好选择 - 它正在执行与Vim中太慢的相同的正则表达式替换。 - Cascabel
我知道这个命令,但我正在寻找只使用vim的解决方案,不使用任何外部工具。 - Frankovskyi Bogdan

1

最好的工具是sed,你可以使用它与:!命令一起使用

所以使用:!sed -e 's/\n/,/g' % > %.tmp ; cat %.tmp > % ; rm %.tmp'

在将其集成到当前文件之前,您需要创建一个带有更改的临时文件


0
$ more file
aaaa
bbbb
cccc
dddd
eeee

$ awk 'NR>1{printf("%s, ", p)}{p=$0}END{print p}' file
aaaa, bbbb, cccc, dddd, eeee

$ sed -e :b -e '$!N;s/\n/, /;tb' file

不是真的。这只是维基百科的剪贴板,但我想有时候维基百科是不可信的。 - ghostdog74

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接