Como posso filtrar um arquivo para linhas que contenham uma string no Sublime Text 2?


74

Quero filtrar um arquivo que estou editando no Sublime Text 2 para que as linhas contenham uma determinada sequência, se possível, incluindo expressões regulares.

Considere o seguinte arquivo:

foo bar
baz
qux
quuux baz

Quando filtrado ba, o resultado deve ser:

foo bar
baz
quuux baz

Como eu posso fazer isso?

Respostas:


87

O Sublime Text 2 é um editor extensível com uma API Python . Você pode criar novos comandos (chamados Plugins ) e disponibilizá-los na interface do usuário.

Adicionando filtro básico TextCommand plugin

No Sublime Text 2, selecione Ferramentas »Novo plug - in e digite o seguinte texto:

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)

Salvar como filter.pyem~/Library/Application Support/Sublime Text 2/Packages/User

Integração com UI

Para adicionar este plug-in ao menu Editar , selecione Preferências ... »Procurar pacotes e abra a Userpasta. Se um arquivo chamado Main.sublime-menunão existir, crie-o. Adicione ou defina o seguinte texto para esse arquivo:

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

Isso irá inserir a filterchamada de comando (essencialmente, filteré transformada FilterCommand().run(…)para a chamada do plugin e Filtro para o rótulo do menu) logo abaixo do wrapcomando. Consulte a etapa 11 aqui para obter uma explicação mais detalhada sobre o motivo.

Para atribuir um atalho de teclado, abra e edite o arquivo Default (OSX).sublime-keymapno OS X ou o equivalente para outros sistemas e digite o seguinte:

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

Isso atribuirá o atalho Fpara este comando.


Para que o comando seja exibido na Paleta de comandos , você precisa criar um arquivo chamado Default.sublime-commands(ou editar um existente) na Userpasta. A sintaxe é semelhante ao arquivo de menu que você acabou de editar:

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

Várias entradas (entre colchetes) precisam ser separadas por vírgulas.

 Capturas de tela de comportamento e integração da interface do usuário

O comando, conforme implementado, filtrará todas as linhas que fazem parte de uma seleção (as linhas inteiras, não apenas as partes selecionadas) ou, se não houver seleção, o buffer inteiro, para uma substring inserida no campo de entrada ( o padrão é a área de transferência - possivelmente inútil de várias linhas -) depois que o comando é acionado. Pode ser facilmente estendido para, por exemplo, suportar expressões regulares ou deixar apenas linhas que não correspondem a uma determinada expressão.

Item do menu

Comando no menu

Entrada da paleta de comandos

Comando com rótulo diferente na paleta de comandos

editor

Usuário digitando texto para filtrar o arquivo com

Resultado após executar o comando

Adicionando suporte para expressões regulares

Para adicionar suporte a expressões regulares, use os seguintes scripts e trechos:

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"
    }
]  

Um segundo comando do plugin, Filter Using Regular Expression , será adicionado abaixo da entrada do menu Filter .

Default.sublime-commands:

[
    { "caption": "Filter Lines in File", "command": "filter" },
    { "caption": "Filter Lines in File Using Regular Expression", "command": "filter_using_regular_expression" }
]

2
Você não deseja publicar isso como um pacote um dia?
Slhck 23/05

11
@slhck Alguém já o fez (com a atribuição apropriada), consulte a resposta do NovicePhysicist. Pelo que li no código, também foi aprimorada bastante sobre essa resposta.
Daniel Beck

Legal, eu não percebi isso!
Slhck 23/05

Qual é o tema que você tem com o SublimeText que oferece cores agradáveis? Ou está apenas mudando a cor da janela?
pal4life

11
@ pal4life: Chama-se Solarized (Light) . Eu acho que o Texto Sublime é enviado com ele. Talvez eu tenha instalado uma alternativa, portanto as cores podem não corresponder exatamente. As capturas de tela estão no OS X, então é daí que a borda da janela e a barra de título são originárias.
Daniel Beck

83

Também existe um algoritmo de filtragem de linha de pobre (ou é preguiçoso?):

  1. Selecionar sequência de interesse
  2. Pressione Alt+ F3para entrar no modo multi-cursor em todas as ocorrências
  3. Pressione Control+ Lpara selecionar a linha inteira (em todas as linhas do cursor)
  4. Seleção de copiar e colar para outro buffer

2
Esta é praticamente a solução mais simples. Bravo!
Gillytech #

Obrigado! Eu prefiro não ter que instalar / aprender outro plugin o máximo possível - Alt + F3 está na minha memória muscular, então a solução acima não é tão buscada para mim.
Olof Bjarnason

Você pode substituir as etapas 3 e 4 por uma única etapa: Ctrl + L.
Andres Riofrio

11
Solução simples e agradável! Eu substituiria a etapa 3 de Ctrl-L para Home, Shift-End. Portanto, não há linhas vazias entre as ocorrências.
jslap

4
Isso mudou minha vida para melhor. Nada será o mesmo novamente.
Shawson 28/07

49

Agora existe um plug - in para filtrar linhas: https://github.com/davidpeckham/FilterLines
Permite filtrar e dobrar códigos com base em strings ou expressões regulares.


Sublime Text Filter Plugin de David Peckham


4
Acabei de instalar este plugin - PERFEITO para o trabalho. Pega um arquivo existente, permite inserir uma frase de filtro e coloca os resultados em uma nova guia.
Nick

4
Concordo, até agora eu sempre sonhei em ter esse tipo de funcionalidade no meu editor de texto.
precisa saber é o seguinte

11
Este plugin é realmente incrível!
Devid

Vim aqui porque um colega de trabalho mencionou algo sobre "Keep Lines" para o emacs e como é útil. Nem sabia que eu precisava desse plugin, adorei!
brandon927

14

Você pode usar os recursos internos do Sublime para fazer isso em 3 a 7 pressionamentos de tecla (sem incluir o regex a ser correspondido).

Etapa 1: selecione várias linhas correspondentes

Opção 1: Para selecionar várias linhas todas as linhas que contêm uma subcadeia

  1. Selecione a sequência de interesse.
  2. Pressione Alt+ F3para selecionar várias ocorrências todas.
  3. Pressione Ctrl+ L(Expanda Seleção para Linha).

Opção 2: para selecionar várias linhas que correspondem a uma regexp

  1. Pressione Ctrl+ Fpara abrir a gaveta Localizar.
  2. Verifique se a correspondência de expressões regulares está ativada ( Alt+ Rpara alternar).
  3. Digite a expressão regular.
  4. Pressione Alt+ Enterpara selecionar vários todos os jogos.
  5. Pressione Ctrl+ L(Expanda Seleção para Linha).

Etapa 2: faça algo com essas linhas

Opção 1: Para se livrar de todas as linhas que não estão selecionadas

  1. Pressione Ctrl+ Cpara copiar.
  2. Pressione Ctrl+ Apara selecionar todos.
  3. Pressione Ctrl+ Vpara substituir a seleção pelas linhas correspondentes.

Opção 2: Para se livrar de todas as linhas que são selecionados

  1. Pressione Ctrl+ Shift+ K(Excluir linha).

Opção 3: Para extrair linhas selecionadas para um novo arquivo

  1. Pressione Ctrl+ Cpara copiar.
  2. Pressione Ctrl+ Npara abrir um novo arquivo.
  3. Pressione Ctrl+ Vpara colar.

Esta é uma excelente lista de comandos!
Chustar 28/05

Super, mas existe uma maneira de remover linhas em branco após colar?
Sergey Senkov 26/09

11
@SergeySenkov Sure! (1) Pressione Ctrl + F para abrir a gaveta Localizar. (2) Verifique se a correspondência de expressões regulares está ativada (Alt + R para alternar). (3) Digite "\ n \ n +" (corresponde a duas ou mais novas linhas consecutivas). (4) Pressione Alt + Enter para multi-selecionar todas as correspondências. (5) Pressione Enter para substituir todas as correspondências por uma única nova linha.
Andres Riofrio
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.