我正在尝试使用VIM删除我创建的XML文件中的重复行。 (我无法重新创建文件,因为ID号会改变。)
该文件看起来像这样:
<tag k="natural" v="water"/>
<tag k="nhd:fcode" v="39004"/>
<tag k="natural" v="water"/>
我正在尝试删除其中一个重复的k =“natural”v =“water”行。当我尝试使用\_
修饰符在我的正则表达式替换中包含换行符时,VIM似乎找不到任何内容。
有关正则表达式或工具使用的任何提示吗?
答案 0 :(得分:4)
首先,您可以使用awk
删除所有重复的行,并保留其顺序。
:%!awk '\!_[$0]++'
如果你不确定是否有其他重复行你不想删除,那么只需添加条件。
:%!awk '\!(_[$0]++ && /tag/ && /natural/ && /water/)'
但是,用正则表达式解析像xml这样的嵌套结构是一个坏主意,恕我直言。
你要关心他们不要一直搞砸。
xmllint
为您提供文件中特定元素的列表:
:!echo "cat //tag[@k='natural' and @v='water']" | xmllint --shell %
您可以逐步删除重复的行。
答案 1 :(得分:1)
而不是使用vim,你会做类似
的事情sort filename | uniq -c | grep -v "^[ \t]*1[ \t]"
找出什么是重复行,然后使用普通搜索来访问它并删除它
答案 2 :(得分:1)
使用'uniq'的答案会遇到'uniq'只找到相邻的重复行,或者数据文件被排序丢失位置信息的问题。
如果不能重复任何行,那么在Perl(或其他具有正则表达式和关联数组支持的脚本语言)中进行相对简单的操作,假设数据源不是非常令人难以置信:
#!/bin/perl -w
# BEWARE: untested code!
use strict;
my(%lines);
while (<>)
{
print if !defined $lines{$_};
$lines{$_} = 1;
}
但是,如果不加选择地使用它,这可能会破坏XML,因为结束标记是合法重复的。怎么避免这个?也许是通过“可以重复”行的白名单?或者,只有带有值的开放标记的行可能会重复消除:
#!/bin/perl -w
# BEWARE: untested code!
use strict;
my(%lines);
while (<>)
{
if (m%^\s*<[^\s>]+\s[^\s>]+%)
{
print if !defined $lines{$_};
$lines{$_} = 1;
}
else
{
print;
}
}
当然,还有(很大程度上有效)的论点,即使用正则表达式处理XML是错误的。这种编码假设XML带有许多方便的换行符;真正的XML可能不包含任何内容,也可能只包含极少数。
答案 3 :(得分:1)
如果您不关心订购,可以选择行然后执行:'<,'>sort u
。它将对重复项进行排序和删除。
答案 4 :(得分:1)
到OP,如果你有bash 4.0
#!/bin/bash
# use associative array
declare -A DUP
file="myfile.txt"
while read -r line
do
if [ -z ${DUP[$line]} ];then
DUP[$line]=1
echo $line >temp
fi
done < "$file"
mv temp "$file"
答案 5 :(得分:1)
使用python删除所有重复的行:
#!/usr/bin/env python
import sys
def remove_identical(filein, fileout) :
lines = list()
for line in open(filein, 'r').readlines() :
if line not in lines : lines.append(line)
fout = open(fileout, 'w')
fout.write(''.join(lines))
fout.close()
remove_identical(sys.argv[1], sys.argv[2])
答案 6 :(得分:1)
简单的正则表达式是不够的。我已经实现了
:DeleteDuplicateLinesIgnoring
我的PatternsOnText plugin中的命令(以及相关命令)。您甚至可以提供{pattern}
以从重复数据删除中排除某些行。
答案 7 :(得分:0)
答案 8 :(得分:0)
似乎bash,python和perl方法可行但你已经在vim中了。那么为什么不创建一个像:
这样的函数function! RemoveDuplicateLines()
let lines={}
let result=[]
for lineno in range(line('$'))
let line=getline(lineno+1)
if (!has_key(lines, line))
let lines[line] = 1
let result += [ line ]
endif
endfor
%d
call append(0, result)
d
endfunction