我想获取一个字符串列表,并且只保留列表中其他位置没有子字符串的字符串。为了说明,我有这个清单:
apple
applesauce
kiwi
mango
mangoes
mangosteen
oranges
pineapples
我想将其缩减为列表中没有任何子字符串的字符串列表。因此,结果列表将是:
apple
kiwi
mango
oranges
请注意,applesauce
和pineapples
已被删除,因为apple
位于列表中的其他位置,并且是这两个字的子字符串。
我发现了一个类似的问题here,但它似乎专门针对前缀,例如ablaze, able, abler, ablest
。基于该方法,我尝试了以下列表的预先排序副本,它只打印了整个列表,甚至没有删除我认为会出现的applesauce
:
awk '$1~r && p in k { next } { k[$1]++; print; r= "^" $1; p=$1 }' fruitsorted.txt
即使它按预期工作,它仍然会在我的列表中遗漏pineapple
。
请注意,在一个极端情况下,如果列表包含字母表中的所有字母(或我猜的ASCII字符集),每个字母都在一个单独的行上,那么无论列表中还有什么,输出都只是字母/字符集。
另外,我的开始列表未分类。我真的不在乎结果列表是否已排序,尽管sort
显然是微不足道的。
理想情况下,我想要一个有点紧凑的shell命令/序列的东西,比如grep / sort / awk,而不是更长的形式Perl / Python /我已经知道如何实现的任何脚本。
感谢。
更新
正如下面的Ed Morton指出的那样,即使对列表进行排序,也可能会破坏一些基本方法,例如:在下面的示例中,假设排序列表的方法可能无法删除berryplum
,因为其子字符串plum
位于其后面。 123所示的第二种方法处理了这种情况。
apple
applesauce
berryplum
kiwi
mango
mangoes
mangosteen
oranges
pineapples
plum
答案 0 :(得分:2)
如果列表已排序,那就非常简单
awk '{for(i in a)if(index($0,i))next;a[$0]}1' file
apple
kiwi
mango
oranges
基本上只是在每个行的数组上循环,并检查行中是否存在元素。如果不是这样,则添加到数组。
对于未排序的列表,这应该有效
awk '{for(i in a){if(index(i,$0)&&$0!=i)delete a[i];if(index($0,i))next}a[$0];next}
END{for(i in a)print i}' file
在Wordlist上测试了性能。
real 0m29.932s
user 0m29.918s
sys 0m0.008s
答案 1 :(得分:1)
$ awk '
NR==FNR { fruits[$0]; next }
{
for (fruit in fruits) {
if ((fruit != $0) && index($0,fruit)) {
next
}
}
final[$0]
}
END {
for (fruit in final) {
print fruit
}
}
' file file
mango
apple
oranges
kiwi
如果你发现有价值的话,你可以把它全部塞进一行:
awk 'NR==FNR{fruits[$0];next} {for (fruit in fruits) if ((fruit != $0) && index($0,fruit)) next; final[$0]} END{for (fruit in final) print fruit}' file file
答案 2 :(得分:0)
对于未排序的列表,这可能有所帮助:
awk 'NR==FNR{f1[NR]=$0;f2[$0]}
END{
for(i=0;i<=NR;i++){
for(j in f2){
if(match(f1[i],j)>=1){
if(length(j)<length(f1[i])){
f1[i]="nullfruit"
}
}
}
}
for(i=0;i<=NR;i++){
if(f1[i]!="nullfruit"){
print f1[i];
}
}
}' filename
apple
kiwi
mango
oranges
注意:非常确定存在更多微妙的解决方案。
答案 3 :(得分:0)
假设:
$ cat f1
apple
applesauce
berryplum
kiwi
mango
mangoes
mangosteen
oranges
pineapples
plum
您可以使用更多循环来避免两次读取文件或关注顺序:
$ awk '{words[$1]}
END{
for (e in words)
for (f in words)
if (f!=e && index(e,f))
not[e]
for (e in words)
if (!(e in not))
print e}' f1
mango
plum
apple
oranges
kiwi