Myślę, że następujące polecenie powinno działać:
:%s/^\(.*\)\(\n\1\)\+$/\1/
Objaśnienie:
Używamy polecenia podstawienia dla całego pliku, aby zmienić pattern
na string
:
:%s/pattern/string/
Oto pattern
jest ^\(.*\)\(\n\1\)\+$
i string
jest \1
.
pattern
można podzielić w następujący sposób:
^\(subpattern1\)\(subpattern2\)\+$
^
i $
dopasuj odpowiednio początek linii i koniec linii.
\(
i \)
służą do załączenia subpattern1
, abyśmy mogli odwołać się później do specjalnego numeru \1
.
Są one również używane do zamykania, subpattern2
dzięki czemu możemy powtórzyć to 1 lub więcej razy z kwantyfikatorem \+
.
subpattern1
jest .*
.
metaznakiem pasującym do dowolnego znaku z wyjątkiem nowej linii i *
jest kwantyfikatorem, który pasuje do ostatniego znaku 0, 1 lub więcej razy. Dopasowuje
więc .*
dowolny tekst nie zawierający nowej linii.
subpattern2
to \n\1
\n
pasuje do nowej linii i \1
pasuje ten sam tekst, który został dopasowany do środka pierwszy \(
, \)
który tutaj jest subpattern1
.
pattern
Można więc odczytać w ten sposób:
początek wiersza ( ^
), po którym następuje dowolny tekst nie zawierający nowej linii ( .*
), a następnie nowy wiersz ( \n
), a następnie ten sam tekst ( \1
), przy czym dwa ostatnie są powtarzane raz lub więcej razy ( \+
), oraz wreszcie koniec linii ( $
) .
Gdziekolwiek pattern
jest dopasowany (blok identycznych linii), polecenie zamiany zastępuje go tym, string
co jest tutaj \1
(pierwsza linia bloku).
Jeśli chcesz zobaczyć, które bloki linii zostaną zmienione bez zmiany czegokolwiek w pliku, możesz włączyć tę hlsearch
opcję i dodać n
flagę podstawienia na końcu polecenia:
:%s/^\(.*\)\(\n\1\)\+$/\1/n
Aby uzyskać bardziej szczegółową kontrolę, możesz również poprosić o potwierdzenie przed zmianą każdego bloku linii, dodając c
zamiast tego flagę podstawienia:
:%s/^\(.*\)\(\n\1\)\+$/\1/c
Aby uzyskać więcej informacji na temat poleceń odczytu podstawienia :help :s
,
dla flagi podmiany :help s_flags
,
na różne metaznakami i kwantyfikatory czytać :help pattern-atoms
,
a dla wyrażenia regularne w vim czytać tego .
Edycja: symbol wieloznaczny naprawił problem w poleceniu, dodając $
na końcu pattern
.
Również BloodGain ma krótszą i bardziej czytelną wersję tego samego polecenia.
$
w tym. W przeciwnym razie zrobi nieoczekiwane rzeczy z linią, która zaczyna się identycznym tekstem jak poprzednia linia, ale ma inne końcowe znaki. Zauważ też, że podstawowe polecenie, które wydałeś, jest funkcjonalnie równoważne z moją odpowiedzią:%!uniq
, ale flagi wyróżnienia i potwierdzenia są ładne.\n
pasuje do końca linii i powinien temu zapobiec, ale tak nie jest. Próbowałem dodać$
zaraz potem.*
bez powodzenia. Spróbuję to naprawić, ale jeśli nie mogę, może usunę odpowiedź lub dodam ostrzeżenie na końcu. Dziękujemy za wskazanie tego problemu.:%s/^\(.*\)\(\n\1\)\+$/\1/
$
pasuje on do końca łańcucha , a nie do końca linii. Z technicznego punktu widzenia nie jest to prawdą, ale po umieszczeniu po nim znaków innych niż kilka wyjątków, pasuje ono dosłownie$
zamiast czegoś specjalnego. Dlatego używanie\n
jest lepsze w przypadku meczów wieloliniowych. (Patrz:help /$
)\n
można go użyć w dowolnym miejscu wyrażenia regularnego, podczas gdy$
prawdopodobnie powinien być używany tylko na końcu. Aby zrobić różnicę między tymi dwoma, zredagowałem odpowiedź, pisząc, która\n
pasuje do nowego wiersza (co instynktownie sprawia, że myślisz, że nadal jest jakiś tekst po), podczas gdy$
pasuje do końca linii (co sprawia, że myślisz, że nic nie ma lewo).Spróbuj wykonać następujące czynności:
Podobnie jak w przypadku odpowiedzi saginaw , wykorzystuje to polecenie Vima: substytut. Wykorzystuje jednak kilka dodatkowych funkcji w celu poprawy czytelności:
\v
oznacza „bardzo magiczne” lub wszystkie znaki z wyjątkiem alfanumerycznych ( A-z0-9 ) i podkreślenia ( _ ) mają specjalne znaczenie.Znaczenie komponentów to:
źródło
\n
i$
.\n
dodaje coś do wzoru: znak nowa linia, który mówi vimowi, że następujący tekst znajduje się w nowej linii. Chociaż$
nic nie dodaje do wzoru, po prostu zabrania dopasowania, jeśli następny znak poza wzorem nie jest nową linią. Przynajmniej to zrozumiałem, czytając twoją odpowiedź i:help zero-width
.^
, ponieważ nie dodaje niczego do wzoru, po prostu uniemożliwia dopasowanie, jeśli poprzedni znak poza wzorem nie jest nową linią ...+
oznacza „powtórz poprzednie wyrażenie (znak lub grupę) 1 lub więcej razy”, ale nie pasuje do niczego. Te^
środki „nie może rozpocząć się w środku łańcucha” i$
oznacza „nie można zakończyć w środku łańcucha.” Zauważ, że nie powiedziałem tam „line”, ale „string”. Vim domyślnie traktuje każdą linię jako ciąg znaków - i to jest miejsce, w którym się\n
pojawia. Mówi Vimowi, aby użył nowej linii, aby spróbować dopasować.Jeśli chcesz usunąć WSZYSTKIE sąsiednie identyczne linie, nie tylko
Hold
, możesz to zrobić niezwykle łatwo z zewnętrznym filtrem od wewnątrzvim
::%!uniq
(w środowisku Unix).Jeśli chcesz to zrobić bezpośrednio
vim
, jest to bardzo trudne. Myślę, że jest na to sposób, ale w ogólnym przypadku jest to bardzo trudne, aby uczynić go w 100% funkcjonalnym i nie opracowałem jeszcze wszystkich błędów.Jednak w tym konkretnym przypadku, ponieważ możesz wizualnie zobaczyć, że następny wiersz, który nie jest duplikatem, nie zaczyna się od tego samego znaku, możesz użyć:
+
Oznacza linię po aktualnej linii. The. odnosi się do bieżącej linii./^[^H]/-
Oznacza linię wcześniej (-
) następnej linii, która nie zaczyna H.Następnie d jest usuwane.
źródło
uniq
to w jaki sposób bym to rozwiązał , wywoływanie (z poziomu vima lub za pomocą powłoki). Po pierwsze, jestem prawie pewien,uniq
że poradzą sobie z liniami, które są puste / wszystkie spacje jako równoważne (nie testowałem tego), ale byłoby to znacznie trudniejsze do uchwycenia za pomocą wyrażenia regularnego. Oznacza to również, że nie „odkrywam na nowo koła”, gdy próbuję wykonać pracę.Odpowiedź oparta na Vimie:
= Zastąp każdą linię, po której następuje co najmniej raz , tą samą linią.
źródło
Jeszcze jedno, zakładając, że Vim 7.4.218 lub nowszy:
Jednak niekoniecznie jest to lepsze niż inne rozwiązania.
źródło
Oto rozwiązanie oparte na starym (2003) vim (golf) autorstwa Prebena Gulberga i Piet Delport.
%g/^\v(.*)\n\1$/d
:Uniq
(odpowiednik:%Uniq
),:1,Uniq
(od początku bufora do bieżącej linii),:Uniq<cr>
(rozwinięty przez vim do:'<,'>Uniq
):h range
)Oto kod:
Uwaga: ich pierwsze próby to:
źródło