Jak mogę filtrować plik pod kątem linii zawierających ciąg znaków w Sublime Text 2?

74

Chcę filtrować plik, który edytuję w Sublime Text 2, aby linie zawierały określony ciąg, jeśli to możliwe, w tym wyrażenia regularne.

Rozważ następujący plik:

foo bar
baz
qux
quuux baz

Kiedy filtrowana ba, wynik powinien być:

foo bar
baz
quuux baz

Jak mogę to zrobić?

Daniel Beck
źródło

Odpowiedzi:

87

Sublime Text 2 to rozszerzalny edytor z API Pythona . Możesz tworzyć nowe polecenia (zwane wtyczkami ) i udostępniać je w interfejsie użytkownika.

Dodanie podstawowej filtrowania wtyczki TextCommand

W Sublime Text 2 wybierz Narzędzia »Nowa wtyczka i wprowadź następujący tekst:

import sublime, sublime_plugin

def filter(v, e, needle):
    # get non-empty selections
    regions = [s for s in v.sel() if not s.empty()]

    # if there's no non-empty selection, filter the whole document
    if len(regions) == 0:
        regions = [ sublime.Region(0, v.size()) ]

    for region in reversed(regions):
        lines = v.split_by_newlines(region)

        for line in reversed(lines):
            if not needle in v.substr(line):
                v.erase(e, v.full_line(line))

class FilterCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        def done(needle):
            e = self.view.begin_edit()
            filter(self.view, e, needle)
            self.view.end_edit(e)

        cb = sublime.get_clipboard()
        sublime.active_window().show_input_panel("Filter file for lines containing: ", cb, done, None, None)

Zapisz jak filter.pyw~/Library/Application Support/Sublime Text 2/Packages/User

Integracja z interfejsem użytkownika

Aby dodać tę wtyczkę do menu Edycja , wybierz Preferencje… »Przeglądaj pakiety i otwórz Userfolder. Jeśli plik o nazwie Main.sublime-menunie istnieje, utwórz go. Dodaj lub ustaw następujący tekst do tego pliku:

[
    {
        "id": "edit",
        "children":
        [
            {"id": "wrap"},
            { "command": "filter" }
        ]
    }
]

Spowoduje to wstawienie filterwywołania polecenia (zasadniczo filterjest przekształcone FilterCommand().run(…)na wywołanie wtyczki i Filtruj na etykiecie menu) tuż pod wrappoleceniem. Zobacz krok 11 tutaj, aby uzyskać bardziej szczegółowe wyjaśnienie, dlaczego tak jest.

Aby przypisać skrót klawiaturowy, otwórz i edytuj plik Default (OSX).sublime-keymapw systemie OS X lub jego odpowiedniku dla innych systemów i wprowadź następujące dane:

[  
    {   
        "keys": ["ctrl+shift+f"], "command": "filter"
    }  
]  

Spowoduje to przypisanie skrótu Fdo tego polecenia.


Aby polecenie pojawiło się w Palecie poleceń , musisz utworzyć plik o nazwie Default.sublime-commands(lub edytować istniejący) w Userfolderze. Składnia jest podobna do pliku menu, który właśnie edytowałeś:

[
    { "caption": "Filter Lines in File", "command": "filter" }
]

Wiele wpisów (w nawiasach klamrowych) należy oddzielić przecinkami.

 Zrzuty ekranu dotyczące zachowania i integracji interfejsu użytkownika

Polecenie, po zaimplementowaniu, odfiltruje wszystkie wiersze, które są częścią zaznaczenia (całe wiersze, nie tylko wybrane części), lub, jeśli nie ma zaznaczenia, cały bufor, dla podłańcucha, który jest wprowadzony do pola wejściowego ( domyślnie jest to schowek (prawdopodobnie bezużyteczny, wieloliniowy) po uruchomieniu polecenia. Można go łatwo rozszerzyć, aby np. Obsługiwał wyrażenia regularne lub pozostawiał wiersze nie pasujące do określonego wyrażenia.

Pozycja w menu

Polecenie w menu

Wprowadzanie palety poleceń

Polecenia z inną etykietą w Palecie poleceń

Redaktor

Użytkownik wprowadza tekst, aby przefiltrować plik

Wynik po wykonaniu polecenia

Dodanie obsługi wyrażeń regularnych

Aby dodać obsługę wyrażeń regularnych, użyj następujących skryptów i fragmentów:

filter.py:

import sublime, sublime_plugin, re

def matches(needle, haystack, is_re):
    if is_re:
        return re.match(needle, haystack)
    else:
        return (needle in haystack)

def filter(v, e, needle, is_re = False):
    # get non-empty selections
    regions = [s for s in v.sel() if not s.empty()]

    # if there's no non-empty selection, filter the whole document
    if len(regions) == 0:
        regions = [ sublime.Region(0, v.size()) ]

    for region in reversed(regions):
        lines = v.split_by_newlines(region)

        for line in reversed(lines):

            if not matches(needle, v.substr(line), is_re):
                v.erase(e, v.full_line(line))

class FilterCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        def done(needle):
            e = self.view.begin_edit()
            filter(self.view, e, needle)
            self.view.end_edit(e)

        cb = sublime.get_clipboard()
        sublime.active_window().show_input_panel("Filter file for lines containing: ", cb, done, None, None)

class FilterUsingRegularExpressionCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        def done(needle):
            e = self.view.begin_edit()
            filter(self.view, e, needle, True)
            self.view.end_edit(e)

        cb = sublime.get_clipboard()
        sublime.active_window().show_input_panel("Filter file for lines matching: ", cb, done, None, None)

Main.sublime-menu:

[
    {
        "id": "edit",
        "children":
        [
            {"id": "wrap"},
            { "command": "filter" },
            { "command": "filter_using_regular_expression" }
        ]
    }
]

Default (OSX).sublime-keymap:

[  
    {   
        "keys": ["ctrl+shift+f"], "command": "filter"
    },
    {
        "keys": ["ctrl+shift+option+f"], "command": "filter_using_regular_expression"
    }
]  

Drugie polecenie wtyczki Filtruj za pomocą wyrażeń regularnych zostanie dodane poniżej pozycji menu Filtr .

Default.sublime-commands:

[
    { "caption": "Filter Lines in File", "command": "filter" },
    { "caption": "Filter Lines in File Using Regular Expression", "command": "filter_using_regular_expression" }
]
Daniel Beck
źródło
2
Nie chcesz opublikować tego jako paczki jednego dnia?
slhck
1
@slhck Ktoś już to zrobił (z odpowiednim przypisaniem), patrz odpowiedź nowicjusza fizyka. Z tego, co przeczytałem w kodzie, poprawiono również nieco tę odpowiedź.
Daniel Beck
Fajnie, nie zauważyłem tego!
slhck
Jaki masz motyw z SublimeText, który daje te ładne kolory? A może po prostu zmienia kolor okna?
pal4life
1
@ pal4life: To się nazywa Solarized (światło) . Wydaje mi się, że Sublime Text jest nawet z nim dostarczany. Być może zainstalowałem alternatywny, więc kolory mogą nie pasować dokładnie. Zrzuty ekranu znajdują się w systemie OS X, stąd pochodzi ramka okna i pasek tytułu.
Daniel Beck
83

Istnieje również algorytm filtrowania linii biednego człowieka (czy jest leniwy?):

  1. Wybierz ciąg zainteresowania
  2. Naciśnij Alt+, F3aby przejść do trybu wielu kursorów dla wszystkich wystąpień
  3. Naciśnij Control+, Laby zaznaczyć całą linię (na każdej linii kursora)
  4. Skopiuj i wklej zaznaczenie do innego bufora
Olof Bjarnason
źródło
2
To jest najprostsze rozwiązanie. Brawo!
gillytech
Dziękuję Ci! Wolę nie instalować / uczyć się innej wtyczki na tyle, na ile to możliwe - Alt + F3 jest w mojej pamięci mięśniowej, więc powyższe rozwiązanie nie jest dla mnie tak dalekie.
Olof Bjarnason
Możesz zastąpić Kroki 3 i 4 jednym krokiem: Ctrl + L.
Andres Riofrio
1
Ładne proste rozwiązanie! Zastąpiłbym krok 3 z Ctrl-L do Home, Shift-End, więc nie ma pustych linii między wystąpieniami.
jslap,
4
To zmieniło moje życie na lepsze. Nic już nie będzie takie samo.
Shawson
49

Jest teraz wtyczka do filtrowania linii: https://github.com/davidpeckham/FilterLines
Umożliwia filtrowanie i składanie kodu na podstawie ciągów lub wyrażeń regularnych.


Wtyczka Sublime Text Filter autorstwa Davida Peckhama

AllanLRH
źródło
4
Właśnie zainstalowałem tę wtyczkę - IDEALNIE do tego zadania. Pobiera istniejący plik, pozwala wprowadzić frazę filtrującą i umieszcza wyniki w nowej karcie.
Nick
4
Zgodziłem się, do tej pory marzyłem tylko o takiej funkcjonalności w moim edytorze tekstów.
Michael12345
1
Ta wtyczka jest naprawdę niesamowita!
Devid
Przybył tutaj, ponieważ współpracownik wspomniał coś o „Keep Lines” dla emacsa i jego przydatności. Nawet nie wiedziałem, że potrzebuję tej wtyczki, absolutnie to uwielbiam!
brandon927,
14

Możesz użyć wbudowanych możliwości Sublime, aby to zrobić w 3 do 7 naciśnięciach klawiszy (bez uwzględnienia wyrażenia regularnego do dopasowania).

Krok 1: Wybierz wiele pasujących linii

Opcja 1: Aby zaznaczyć wiele linii zawierających podłańcuch

  1. Wybierz ciąg zainteresowania.
  2. Naciśnij Alt+, F3aby wybrać wszystkie wystąpienia wielokrotnie.
  3. Naciśnij Ctrl+ L(Rozwiń zaznaczenie do linii).

Opcja 2: Aby zaznaczyć wiele linii pasujących do wyrażenia regularnego

  1. Naciśnij Ctrl+, Faby otworzyć szufladę Znajdź.
  2. Upewnij się, że dopasowanie wyrażeń regularnych jest włączone ( Alt+ Rprzełączanie).
  3. Wpisz wyrażenie regularne.
  4. Naciśnij Alt+, Enteraby zaznaczyć wszystkie mecze wielokrotnym wyborem.
  5. Naciśnij Ctrl+ L(Rozwiń zaznaczenie do linii).

Krok 2: Zrób coś z tymi liniami

Wariant 1: Aby pozbyć się wszystkich linii, które nie zostały wybrane

  1. Naciśnij Ctrl+, Caby skopiować.
  2. Naciśnij Ctrl+, Aaby zaznaczyć wszystko.
  3. Naciśnij Ctrl+, Vaby zastąpić zaznaczenie pasującymi liniami.

Wariant 2: Aby pozbyć się wszystkich linii, które wybrane

  1. Naciśnij Ctrl+ Shift+ K(Usuń linię).

Opcja 3: Aby wyodrębnić wybrane linie do nowego pliku

  1. Naciśnij Ctrl+, Caby skopiować.
  2. Naciśnij Ctrl+, Naby otworzyć nowy plik.
  3. Naciśnij Ctrl+, Vaby wkleić.
Andres Riofrio
źródło
To doskonała lista poleceń!
chustar
Super, ale czy istnieje sposób na usunięcie pustych linii po wklejeniu?
Siergiej Senkow
1
@SergeySenkov Sure! (1) Naciśnij Ctrl + F, aby otworzyć szufladę Znajdź. (2) Upewnij się, że dopasowanie wyrażeń regularnych jest włączone (Alt + R, aby przełączyć). (3) Wpisz „\ n \ n +” (dopasowuje dwie lub więcej kolejnych linii). (4) Naciśnij klawisze Alt + Enter, aby zaznaczyć wszystkie mecze wielokrotnego wyboru. (5) Naciśnij Enter, aby zastąpić wszystkie dopasowania pojedynczą nową linią.
Andres Riofrio