2017-06-23 7 views
2

文字列のリストを取得し、リストのどこかに部分文字列を持たないものだけを残したいとします。私は他の場所で、リスト内の任意の部分文字列を持っていない文字列のリストにそれを減らしたいLinux:文字列のリストをリスト内の他の場所に持っていればリストから文字列を削除してください

apple 
applesauce 
kiwi 
mango 
mangoes 
mangosteen 
oranges 
pineapples 

:説明するために、私はこのリストを持っています。だから、結果のリストは次のようになります。appleは別の場所リストであり、両方のそれらの単語の部分文字列であるため、削除された

apple 
kiwi 
mango 
oranges 

applesauceこととpineapples

私は同様の質問を見つけた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で簡単です。

理想的には、より長い形式のPerl/Python /私がすでに実装する方法を知っているスクリプトとは対照的に、grep/sort/awkのようなコンパクトなシェルコマンド/シーケンスが理想的です。

ありがとうございました。

更新

としても、かもしれ台無しにいくつかの基本的なアプローチ、例えば、リストを並べ替え、下記のエド・モートンが指摘しました次の例では、並べ替えられたリストがの後に来るので、おそらくberryplumを削除できないと仮定しているアプローチです。 123で示される第2のアプローチは、このケースを扱う。リストがソートされている場合の要素がラインに存在する場合

apple 
applesauce 
berryplum 
kiwi 
mango 
mangoes 
mangosteen 
oranges 
pineapples 
plum 

答えて

2

はそれが

awk '{for(i in a)if(index($0,i))next;a[$0]}1' file 

apple 
kiwi 
mango 
oranges 

は、基本的にはちょうど各行の配列をループかなり簡単だし、チェックします。そうでない場合は配列に追加します。ソートされていないリストについて

これは、パフォーマンスのためにWordlistでテスト

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 

を動作するはずです。

real 0m29.932s 
user 0m29.918s 
sys  0m0.008s 
+0

私はあなたの提案を試みたが、うまくいかなかった。次のように試してみましょう: 'awk '{if(i in a)if(index($ 0、i))next; a [$ 0]} 1' fruitsorted.txt'ここで' fruitsorted.txt'は私が示したリストです私の質問のトップこれにより、何も削除されずにリスト全体が再印刷されます。私はCygwin Bash(minntty 2.7.7)を使用しています。何か不足していますか?ありがとう。 – SSilk

+0

@SSilkファイルにキャリッジリターンが含まれていますか? – 123

+0

@EdMorton更新されたコマンドは、 – 123

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 

注:かなり確信してより多くの微妙なソリューションが存在します。

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 

あなたは貴重なことを見つけた場合は、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 
+0

このアプローチは、下記の123に示す2番目の例でカバーしていない特殊なケースをカバーしていますか?彼はもう少しコンパクトに見えますが、もっと短い変数名を使用しているかもしれません。 – SSilk

+0

@SSilk私が言うことができる限り、どちらも同じケースをカバーしています。唯一の違いは、すべての行が配列に読み込まれ、更新するためにファイルを2回読み込みますが、鉱山では、行ごとに行ごとに行が追加され、ファイルはonce.other以外で読み込まれます。同じ。とにかくどちらの答えも同じ結果を生み出すだろう。 – 123

+0

右の変数名は短いだけで、空白はありません。あなたが私の化粧品の空白をすべて削除し、すべての変数名を単一の文字に変更すると、それは123よりわずかに簡潔です。私は知っている**私の解決策はすべての可能なケースをカバーしています。もしidkが123sのミスをしているのであれば、それは私の 'fruits'アレイに相当するものを作っているので** **おそらく**チェックしなければならないファイルの早い方で、すでにスキップしていました。私は本当に分かりません。すべてのケースを考慮して考えてください。 –

0

$ cat f1 
apple 
applesauce 
berryplum 
kiwi 
mango 
mangoes 
mangosteen 
oranges 
pineapples 
plum 

あなたは、ファイルの読み込みを避けるために少しより多くのループを使用することができます2回または注文を心配している:

$ 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 
関連する問題