例如,ina:bc:d:a:hi:p:a
删除重复项a
和 in apple:orange:apple:.:pear:mango:.:apple
- 删除重复项apple
答案1
GNUawk解决方案(所有分隔符将被保留):
s="apple:orange:apple:.:pear:mango:.:apple"
awk '{ len=split($0,a,/:|:\.:/,seps);
for(i=1;i<=len;i++) printf "%s%s",(!w[a[i]]++? a[i]:""),(i==len? "":seps[i]);
print "" }' <<<"$s"
len=split($0,a,/:|:\.:/,seps)
- 将字符串分成由正则表达式模式分隔的片段/:|:\.:/
,并将这些片段存储在数组中a
,并将分隔符字符串存储在seps
数组中。len
- 包含由于分割而创建的元素/块的数量
输出:
apple:orange::.:pear:mango:.:
答案2
订购Python解决方案
如果顺序很重要,我们可以在 python 中以单行代码执行以下操作:
$ python -c 'import sys;from collections import OrderedDict; d=OrderedDict( (i,True) for i in sys.argv[1].split(":") );print ":".join(d.keys())' 'apple:orange:apple:.:pear:mango:.:apple'
apple:orange:.:pear:mango
有点长,所以我们可以把它写成一个小脚本:
#!/usr/bin/env python
from collections import OrderedDict
import sys
d=OrderedDict( (i,True) for i in sys.argv[1].split(":") )
print ":".join(d.keys())
并按如下方式使用它:
$ ./uniq_tokens.py 'apple:orange:apple:.:pear:mango:.:apple'
apple:orange:.:pear:mango
其工作方式:
- 我们将要处理的字符串作为命令行参数给出,因此我们使用
sys
module 来引用sys.argv[1]
sys.argv[1]
get 使用:
分隔符分割成标记(i,True) for i in sys.argv[1].split(":")
允许我们创建具有两个值的元组列表,其中True
只是虚拟值OrderedDict
然后获取这些并创建键值对的字典。这是一种“廉价”的制作方法有序集和列表理解作为字典理解的替代方案。如果字符串已经作为键存在,它将保持唯一(除非做了一些不必要的事情)":".join()
将允许我们获取我们分割的所有标记(因此我们d.keys()
在这里使用),然后将其转换回一个漂亮的整个字符串,并用:
- 打印是不言自明的。
无序(但更短)的Python解决方案
如果顺序不重要,我们可以得到一个更短的解决方案(但这更多的是为了好玩而不是实际应用 - 可能 99% 的时间你都想保留令牌的顺序):
$ python -c 'import sys;print ":".join(set(sys.argv[1].split(":")))' 'a:bc:d:a:hi:p:a'
a:p:hi:d:bc
其工作方式很简单:
- 我们将所需的字符串作为命令行参数传递,因此我们需要
import sys
将第一个命令行参数引用为sys.argv[1]
- 现在,让我们打开第二部分;
sys.argv[1].split(":")
为我们提供了一个最初是整个字符串的标记列表,我们将其用作:
各个标记的分隔符 set()
将采用上面提到的字符串列表并为我们提供唯一值- 现在,我们需要将这一字符串集合转换回一个完整的字符串,这就是为什么我们使用分隔符
":".join()
再次将所有标记拼接在一起。:
print
是不言自明的。请注意,这是 Python 2.7 语法。用于print()
Python 3
这是使用其他字符串的测试:
$ python -c 'import sys;print ":".join(set(sys.argv[1].split(":")))' 'apple:orange:apple:.:pear:mango:.:apple'
orange:mango:pear:apple:.
答案3
您可以使用 Perl 的哈希数据类型来删除重复项:
$ cat ./remove_dup.pl
#!/usr/bin/perl -w
use strict;
my $input = shift;
my %seen;
my $order=1;
foreach my $dir ( split /:/, $input ) {
$seen{$dir} = $order++ unless ($seen{$dir}) ;
}
my $output = join( ':', sort { $seen{$a} <=> $seen{$b} } keys(%seen));
print $output . "\n";
演示:
$ ./remove_dup.pl a:bc:d:a:hi:p:a
a:bc:d:hi:p
$ ./remove_dup.pl apple:orange:apple:.:pear:mango:.:apple
apple:orange:.:pear:mango
答案4
一个bash
办法:
strjoin() { local IFS="$1"; echo "${*:2}"; }
dedup() {
declare -A valbag
IFS=: read -r -a vals <<<"$1"
for ((i=0; i < ${#vals[@]}; i++)); do
(( valbag[${vals[i]}]++ > 0 )) && vals[i]=''
done
strjoin : "${vals[@]}"
}
$ dedup apple:orange:apple:.:pear:mango:.:apple
apple:orange::.:pear:mango::
$ dedup 'a:bc:d:a:hi:p:a'
a:bc:d::hi:p:
这满足了您评论中将所有冒号保留在原位并仅清空冒号之间的重复项的要求。