2017-01-03 1 views
-1

Ich habe eine Herausforderung, in einer Datei zu suchen, wenn ein Satz 2 identische aufeinanderfolgende Wörter enthält. Wenn ja, drucken Sie das Wort; Andernfalls drucken Sie den Satz nicht.Entfernen Sie doppelte Wörter und drucken Sie nur Zeilen, in denen dies auftritt

Beispiel:

abc2 1 def2 3 abc2 
F4 
-------------- 
dea 123 123 zy45 
12 12 
abc cd abc cd 
xyz%[email protected]! xyz%[email protected]! kk 
xyzxyz 
abc h h h h 

Nach dem Ausführen des Programms wird der Ausgang sein:

dea 123 zy45 
12 
xyz%[email protected]! kk 
abc h h h 
3 

Das ist, was ich bisher habe:

sed '/\([^\([^ ]\+\)[ ]\+\1]\)/d' F4 >|tmp 

ich dies habe bisher aber Dies ist nur zwischen den Sätzen, die das Doppelwort haben und den Sätzen, die das nicht haben.

+0

Schauen Sie sich bitte [editing-help] (http://stackoverflow.com/editing-help) an. – Cyrus

+0

Um die Zeile neu zu schreiben, um eines der doppelten Wörter loszuwerden, müssen Sie einen 's ///' Befehl verwenden, nicht 'd'. – Barmar

+0

Sie scheinen ein zusätzliches '' 'und' '' in Ihrem Befehl zu haben, also sehe ich nicht, wie es das tut, was Sie sagen. – Barmar

Antwort

1

Ihre sed Ausdruck war ziemlich genau. Allerdings benötigt es einige Mangeln, damit es funktioniert:

$ sed -nr 's/\b(\S+)\s+\1(\s|$)/\1/p' file 
dea 123 zy45 
12 
xyz%[email protected]! kk 
abc h h h 

Die Idee der ist bereits umgesetzt: Match ein gegebenes Wort mit [^ ] und sehen Sie, wenn Sie es mit \1 wieder übereinstimmen. Was ich hinzugefügt habe, ist all dies mit \1 ersetzt werden, so dass der wiederholte Block verschwindet.

Anstelle von [^ ] ist es auch sinnvoll, \S und statt [ ], \s zu verwenden. Beachten Sie auch die Verwendung von \b als Wortgrenze, um falsche Positive wie fedorqui qui und die Verwendung von \1(\s|$) zu verhindern, um andere falsche Positive wie hello helloa zu verhindern (danke für die Beispiele WalterA!). Beachten Sie die Verwendung von \s|$, um entweder ein Leerzeichen oder das Ende der Zeile zu entsprechen; \b passt zu jedem Nicht-Wort-Zeichen, was es für den Fall mit xyz%[email protected]! kk nicht sinnvoll macht.

Um zu verhindern, dass alle Zeilen gedruckt werden, verwenden wir sed -n. Auf diese Weise drucken wir nur (mit) diejenigen, die den regulären Ausdruck durchlaufen, der definiert wurde.

Beachten Sie die Verwendung von -r, um all jene zu entfernen, die zu Sammelgruppen entkommen. Ohne sie würde der Befehl:

sed -n 's/\b\([^ ]\+\)[ ]\+\1/\1/p' file 

Testen sie es mit einem umfassenderen Eingang:

$ cat a 
abc2 1 def2 3 abc2 
F4 
-------------- 
dea 123 123 zy45 
12 12 
abc cd abc cd 
xyz%[email protected]! xyz%[email protected]! kk 
xyzxyz 
fedorqui qui 
hello helloa 
abc h h h h 
$ sed -nr 's/\b(\S+)\s+\1(\s|$)/\1/p' a 
dea 123zy45 
12 
xyz%[email protected]!kk 
abc hh h 
+0

Sie stimmen einen Teilstring wie 'fedorqui qui' überein. –

+0

@WalterA sehr guter Punkt! Eine Wortgrenze wurde hinzugefügt, um dies zu verhindern. Vielen Dank. – fedorqui

+0

Ihre Änderung mit '\ b' fixierte auch 'abc cd abc cd', die in' abcd abc cd' abgeschnitten wurde. Aber wie wäre es mit der zweiten Saite als Teilstring der ersten wie "Walter Waltera"? –

0

Ich war für eine sed Lösung, die einfach zu sein schien. vielleicht in diesem Fall awk besser ist (F4 ist die Eingabedatei):

awk '{ 
     for (i=2; i<=NF; i++) { 
      if ($(i-1)==$i) { 
       $i=""; 
       printf("%s\n", $0); 
       break; 
      } 
     } 
    }' F4 

Ich bin nicht komplett glücklich mit dieser Lösung, da sie eine doppelte FieldSep in $0 nach dem verdoppelten Wort löschen lassen, aber buchstäblich die OP tat nicht sehen, dass ein Leerzeichen oder eine Registerkarte auch gelöscht werden sollte.

Verwandte Themen