我有一个带有文本字段的制表符分隔数据文件,其中某些字段具有重复信息,以分号分隔:
2000;2000
05/19/2016;05/19/2016
foo;foo
我怎样才能sed
删除重复的部分?分号经常出现在其他字段中,所以我想我需要搜索在分号两侧找到的字符串,由制表符绑定,即\t$1;$1\t
(\t
表示制表符),然后替换为$1
不带分号和重复的相同实例场地。我对其他文本解析命令持开放态度。
答案1
在文件中使用此内容tabbed.input
(没有空格,所有连续的空格都是一个制表符):
abc bd c 2000;2000 d 2;00;2;01
e 05/19/2016;05/19/2016 foo;foo f g
以下Python程序:
def cleaned(f):
length = len(f)
if (length % 2) == 0:
return f # even number of characters in field, middle one never ';'
half_way = length // 2
if f[half_way] != ';':
return f
before, after = f[:half_way], f[half_way+1:]
if before == after:
return before
return f
with open('tabbed.input') as fp:
for line in fp:
fields = line[:-1].split('\t')
cleaned_fields = [cleaned(f) for f in fields]
print('\t'.join(cleaned_fields))
你的输出将是:
012345670123456701234567012345670123456701234567
abc bd c 2000 d 2;00;2;01
e 05/19/2016 foo f g
通过测试偶数个字符并;
在字段中间包含“ ”,当重复数据包含“ ;
”时,这甚至可以工作
答案2
POSIXly:
sed -e 's/\([^;][^;]*\);\1/\1/g' <file
您还可以使用:
sed -E 's/([^;]+);\1/\1/g' <file
它得到了 GNU 和 BSD sed 的支持,并将成为下一个 POSIX 的标准。
答案3
和perl
:
perl -F'\t' -e 'map {s/(.+);$1/$1/} @F; print join("\t",@F)'
与该sed
解决方案不同,该解决方案单独处理每个字段,从而防止检测和删除跨字段重复的可能性(例如foo;<TAB>foo
- TAB 和第二个字段foo
被该解决方案删除sed
,但不是被该perl
解决方案删除)。根据您的输入数据,这在您的实际使用中可能不是问题。
以下版本消除了字段中的多个重复项(例如a;b;a;b;a;b
--> a;b
):
perl -F'\t' -e 'map {while(/(.+);$1/) {s/(.+);$1/$1/g}} @F;print join("\t",@F)'
注意:这些假设是最新版本的perl
,其中-F
暗示-a
和-n
。如果您有旧版本,请使用perl -F'\t' -ane '...'