sed
Odpowiedź wypracowałem niedługo po tym, jak opublikowałem to pytanie; jak dotąd nikt inny nie korzystał sed
:
sed '$!N;/^\(.*\)\n\1$/d;P;D'
Trochę zabawy z bardziej ogólnym problemem (co z usuwaniem linii w zestawach trzech? Lub czterech lub pięciu?) Zapewniło następujące rozszerzalne rozwiązanie:
sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
Rozszerzony, aby usunąć trzykrotnie linii:
sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
Lub usunąć quady z linii:
sed -e ':top' -e '$!{/\n.*\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1\n\1$/d;P;D' temp
sed
ma dodatkową przewagę nad większością innych opcji, a mianowicie jego zdolność do prawdziwego działania w strumieniu, przy czym nie potrzeba więcej pamięci niż rzeczywista liczba wierszy do sprawdzenia pod kątem duplikatów.
Jak zauważył cuonglm w komentarzach , ustawienie języka na C jest konieczne, aby uniknąć błędów w prawidłowym usuwaniu wierszy zawierających znaki wielobajtowe. Tak więc powyższe polecenia stają się:
LC_ALL=C sed '$!N;/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
# Etc.
C
, w przeciwnym razie w ustawieniach wielobajtowych niepoprawny znak w tych ustawieniach regionalnych spowoduje niepowodzenie polecenia.Nie jest zbyt elegancki, ale jest tak prosty, jak mogę wymyślić:
Funkcja substr () po prostu przycina dane
uniq
wyjściowe. Będzie to działać, dopóki nie będzie więcej niż 9 999 999 duplikatów linii (w takim przypadku dane wyjściowe uniq mogą rozlewać się na ponad 9 znaków).źródło
uniq -c input | awk '{if ($1 %2 == 1) { print $2 } }'
i wydawało się, że działa równie dobrze. Czy jest jakiś powód, dla któregosubstr
wersja jest lepsza?$2
nie$NF
byłaby bardziej niezawodna?foo bar
.uniq
(przynajmniej w jądrach GNU) wydaje się, że niezawodnie używają dokładnie 9 znaków przed samym tekstem; Nie mogę tego nigdzie udokumentować i nie ma go w specyfikacji POSIX .Spróbuj tego
awk
skryptu poniżej:Zakłada się, że
lines.txt
plik jest posortowany.Test:
źródło
Z
pcregrep
dla danej próbki:lub bardziej ogólnie:
źródło
Jeśli dane wejściowe są posortowane:
źródło
pineapple\napple\ncoconut
A wynik topinecoconut
.\n
zamiast$
biorąc pod uwagę/m
modyfikator, ale potem zdałem sobie sprawę, że za pomocą$
byłoby zostawić pusty wiersz w miejsce usuniętych linii. Wygląda teraz dobrze; Usunąłem niepoprawną wersję, ponieważ po prostu dodała hałas. :)Lubię
python
to, na przykład zpython
wersją 2.7+źródło
Ponieważ zrozumiałem pytanie, które wybrałem awk, używając skrótu każdego rekordu, w tym przypadku zakładam, że RS = \ n, ale można to zmienić, aby rozważyć inne rodzaje aranżacji, można ustawić, aby rozważyć parzysta liczba powtórzeń zamiast nieparzystych z parametrem lub małym dialogiem. Każda linia jest używana jako skrót, a jej liczba jest zwiększana, na końcu pliku tablica jest skanowana i drukuje każdą parzystą liczbę rekordów. Podaję liczbę, aby sprawdzić, ale usunięcie [x] wystarczy, aby rozwiązać ten problem.
HTH
liczy kod
Przykładowe dane:
Przykładowy przebieg:
źródło
awk
kodu, ale niestetyawk
tablice asocjacyjne wcale nie są uporządkowane, ani też nie zachowują porządku.sort
.!=0
wynika to z tego, w jaki sposóbawk
konwertuje liczby na wartości prawda / fałsz, dzięki czemu można to zredukować doawk '{a[$0]++}END{for(x in a)if(a[x]%2)print x}'
Jeśli dane wejściowe są posortowane, co z tym
awk
:źródło
z perlem:
źródło
Używając konstrukcji powłoki,
źródło
$b
).Zabawna łamigłówka!
W Perlu:
Szczegółowo w Haskell:
Tersely in Haskell:
źródło
wersja: Używam „ograniczników”, aby uprościć wewnętrzną pętlę (zakłada, że pierwszy wiersz nie jest,
__unlikely_beginning__
i zakłada, że tekst nie kończy się na linii:__unlikely_ending__
i dodaj tę specjalną linię separatora na końcu wprowadzanych linii. algorytm może przyjąć zarówno:)Więc :
źródło