我有一个包含以下行的文件:
one one
one one
two two two
one one
three three
one one
three three
four
我想从文件中删除所有出现的重复行,只留下非重复行。因此,在上面的示例中,结果应为:
two two two
four
我看到了this answer to a similar looking question。我尝试修改ex one-liner,如下所示:
:syn clear Repeat | g/^\(.*\)\n\ze\%(.*\n\)*\1$/exe 'syn match Repeat "^' . escape(getline ('.'), '".\^$*[]') . '$"' | d
但它不会删除所有重复的行,它只会删除一些事件。
我怎样才能在vim中这样做?或具体如何在vim中使用ex?
澄清一点,我不是在寻找sort u
。
答案 0 :(得分:2)
如果您使用的是具有awk功能的Linux机箱,则该系列可满足您的需求:
:%!awk '{a[$0]++}END{for(x in a)if(a[x]==1)print x}'
答案 1 :(得分:2)
如果您可以访问UNIX样式的命令,则可以执行以下操作:
:%!sort | uniq -u
-u
命令的uniq
选项可执行您需要的任务。从uniq
命令的帮助文本:
-u, --unique
only print unique lines
但是我应该注意,这个答案假定您不介意输出与输入文件可能已经存在的任何排序顺序不匹配。
答案 2 :(得分:1)
假设您使用的是UNIX衍生产品,下面的命令应该可以执行您想要的操作:
:sort | %!uniq -u
uniq
仅适用于排序行,因此我们必须首先使用Vim的buit-in :sort
命令对它们进行排序以保存一些输入(默认情况下它适用于整个缓冲区,因此我们不需要传递一个范围,这是一个内置命令,所以我们不需要!
)。
然后我们通过uniq -u
过滤整个缓冲区。
答案 3 :(得分:1)
它不保留剩余行的顺序,但这似乎有效:
:sort|%s/^\(.*\)\n\%(\1\n\)\+//
(这个版本是@Peter Rincker的想法,稍微改正一下。)在vim 7.3上,以下甚至更短的版本有效:
:sort | %s/^\(.*\n\)\1\+//
不幸的是,由于正则表达式引擎之间的差异,这不再适用于vim 7.4(包括补丁1-52)。
答案 4 :(得分:1)
答案 5 :(得分:0)
从here获取代码并修改它以删除行而不是突出显示它们,你会得到这个:
function! DeleteDuplicateLines() range
let lineCounts = {}
let lineNum = a:firstline
while lineNum <= a:lastline
let lineText = getline(lineNum)
if lineText != ""
if has_key(lineCounts, lineText)
execute lineNum . 'delete _'
if lineCounts[lineText] > 0
execute lineCounts[lineText] . 'delete _'
let lineCounts[lineText] = 0
let lineNum -= 1
endif
else
let lineCounts[lineText] = lineNum
let lineNum += 1
endif
else
let lineNum += 1
endif
endwhile
endfunction
command! -range=% DeleteDuplicateLines <line1>,<line2>call DeleteDuplicateLines()
答案 6 :(得分:0)
这并不比@Ingo Karkat的答案简单,但它更灵活一些。就像那个答案一样,这会使剩余的行保持原始顺序。
function! RepeatedLines(...)
let first = a:0 ? a:1 : 1
let last = (a:0 > 1) ? a:2 : line('$')
let lines = []
for line in range(first, last - 1)
if index(lines, line) != -1
continue
endif
let newlines = []
let text = escape(getline(line), '\')
execute 'silent' (line + 1) ',' last
\ 'g/\V' . text . '/call add(newlines, line("."))'
if !empty(newlines)
call add(lines, line)
call extend(lines, newlines)
endif
endfor
return sort(lines)
endfun
:for x in reverse(RepeatedLines()) | execute x 'd' | endfor
一些注意事项:
:help list-functions
/\V
(非常没有魔法)所以我需要在搜索模式中逃脱的唯一字符就是反斜杠本身。 :help /\V
答案 7 :(得分:0)
请使用perl,perl可以轻松实现!
use strict;use warnings;use diagnostics;
#read input file
open(File1,'<input.txt') or die "can not open file:$!\n";my @data1=<File1>;close(File1);
#save row and count number of row in hash
my %rownum;
foreach my $line1 (@data1)
{
if (exists($rownum{$line1}))
{
$rownum{$line1}++;
}
else
{
$rownum{$line1}=1;
}
}
#if number of row in hash =1 print it
open(File2,'>output.txt') or die "can not open file:$!\n";
foreach my $line1 (@data1)
{
if($rownum{$line1}==1)
{
print File2 $line1;
}
}
close(File2);
答案 8 :(得分:0)