86

I want to filter a file I'm editing in Sublime Text 2 for lines contain a certain string, if possible including regular expressions.

Consider the following file:

foo bar
baz
qux
quuux baz

When filtered for ba, the result should be:

foo bar
baz
quuux baz

How can I do that?

4 Answers 4

104

There is also a poor man's line filtering algorithm (or is it lazy?):

  1. Select string of interest
  2. Hit Alt+F3 to go into multi-cursor mode on all occurrences
  3. Hit Control+L to select entire line (on every cursor line)
  4. Hit Esc to leave the search input field.
  5. Copy-paste selection to another buffer.
  6. (If needed) Remove the empty lines. E.g. by sorting lines and removing the empty ones or with Edit -> Permute Lines -> Unique and removing the remaining single line.
8
  • 2
    This is pretty much the simplest solution. Bravo!
    – gillytech
    Commented Oct 1, 2014 at 22:03
  • Thank you! I prefer not having to install/learn another plugin for as much as possible - Alt+F3 is in my muscle memory so the above solution is actually not that far fetched for me. Commented Oct 4, 2014 at 18:42
  • 3
    Nice simple solution! I would replace step 3 from Ctrl-L to Home , Shift-End So there is no empty lines between occurences.
    – jslap
    Commented Oct 8, 2015 at 13:02
  • 7
    This changed my life for the better. Nothing will ever be the same again.
    – Shawson
    Commented Jul 28, 2016 at 15:07
  • 5
    for those on mac, replace step 2 with ctl + cmd + G, and step 3 with cmd + L - works great!
    – Alex
    Commented Nov 20, 2020 at 14:56
89

Sublime Text 2 is an extensible editor with a Python API. You can create new commands (called Plugins) and make them available from the UI.

Adding basic filtering TextCommand plugin

In Sublime Text 2, select Tools » New Plugin and enter the following text:

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)

Save as filter.py in ~/Library/Application Support/Sublime Text 2/Packages/User

Integration with UI

To add this plugin to the Edit menu, select Preferences… » Browse Packages and open the User folder. If a file called Main.sublime-menu doesn't exist, create it. Add or set the following text to that file:

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

This will insert the filter command call (essentially, filter is transformed to FilterCommand().run(…) for the plugin call and Filter for the menu label) just below the wrap command. See step 11 here for a more detailed explanation why that is.

To assign a keyboard shortcut, open and edit the file Default (OSX).sublime-keymap on OS X, or the equivalent for other systems, and enter the following:

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

This will assign the shortcut F to this command.


To make the command show up in the Commands Palette, you need to create a file named Default.sublime-commands (or edit an existing one) in the User folder. The syntax is similar to the menu file you just edited:

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

Multiple entries (enclosed by curly brackets) need to be separated by commas.

 Behavior and UI integration screenshots

The command, as implemented, will filter all lines that are part of a selection (the entire lines, not just the selected parts), or, if no selection exists, the entire buffer, for a substring that is entered to the input field (default is the — possibly useless multi-line — clipboard) after the command is triggered. It can easily be extended to e.g. support regular expressions, or only leave lines not matching a certain expression.

Menu item

Command in menu

Commands palette entry

Command with different label in Commands Palette

Editor

User entering text to filter file with

Result after executing the command

Adding support for Regular Expressions

To add support for regular expressions, use the following scripts and snippets instead:

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

A second plugin command, Filter Using Regular Expression will be added below the Filter menu entry.

Default.sublime-commands:

[
    { "caption": "Filter Lines in File", "command": "filter" },
    { "caption": "Filter Lines in File Using Regular Expression", "command": "filter_using_regular_expression" }
]
6
  • 2
    Don't you want to publish this as a package one day?
    – slhck
    Commented May 23, 2013 at 12:53
  • 1
    @slhck Someone already did (with appropriate attribution), see NovicePhysicist's answer. From what I read in the code, it was improved quite a bit over this answer as well.
    – Daniel Beck
    Commented May 23, 2013 at 13:51
  • Cool, I didn't notice that!
    – slhck
    Commented May 23, 2013 at 13:55
  • What is that theme you have with the SublimeText that gives that nice colors? Or is it just changing the window color?
    – pal4life
    Commented Jul 16, 2014 at 1:22
  • 1
    @pal4life: It's called Solarized (Light). I think Sublime Text even ships with it. I might have installed an alternative one though, so the colors might not match exactly. Screenshots are on OS X, so that's where the window border and title bar are from.
    – Daniel Beck
    Commented Jul 16, 2014 at 7:31
56

There's now a plugin for filtering lines: https://github.com/davidpeckham/FilterLines
It allows filtering and code folding based on strings or regular expressions.


Sublime Text Filter Plugin by David Peckham

4
  • 5
    Just installed this plugin - PERFECT for the job. Takes an existing file, lets you enter a filter phrase and puts the results in a new tab.
    – Nick
    Commented Oct 10, 2013 at 7:28
  • 4
    Agreed, until now I have only ever dreamed of having this sort of functionality in my text editor. Commented Jan 30, 2014 at 0:35
  • 1
    This plugin is really awesome!
    – Devid
    Commented Mar 2, 2015 at 10:32
  • Came here because a coworker mentioned something about "Keep Lines" for emacs and how useful it is. Didn't even know I needed this plugin, absolutely love it!
    – brandon927
    Commented Mar 13, 2015 at 17:36
17

You can use Sublime's built-in capabilities to do this in 3 to 7 key strokes (not including the regex to be matched).

Step 1: Multi-select all matching lines

Option 1: To multi-select all lines containing a substring

  1. Select the string of interest.
  2. Hit Alt+F3 to multi-select all occurences.
  3. Hit Ctrl+L (Expand Selection to Line).

Option 2: To multi-select all lines matching a regexp

  1. Hit Ctrl+F to open the Find drawer.
  2. Make sure Regular Expression matching is enabled (Alt+R to toggle).
  3. Type in the regular expression.
  4. Hit Alt+Enter to multi-select all matches.
  5. Hit Ctrl+L (Expand Selection to Line).

Step 2: Do something with those lines

Option 1: To get rid of all lines that are not selected

  1. Hit Ctrl+C to copy.
  2. Hit Ctrl+A to select all.
  3. Hit Ctrl+V to replace selection with the matching lines.

Option 2: To get rid of all lines that are selected

  1. Hit Ctrl+Shift+K (Delete Line).

Option 3: To extract selected lines to a new file

  1. Hit Ctrl+C to copy.
  2. Hit Ctrl+N to open a new file.
  3. Hit Ctrl+V to paste.
3
  • This is an excellent list of commands!
    – chustar
    Commented May 28, 2015 at 23:32
  • Super, but is there way to remove blank lines after paste? Commented Sep 26, 2016 at 10:09
  • 1
    @SergeySenkov Sure! (1) Hit Ctrl+F to open the Find drawer. (2) Make sure Regular Expression matching is enabled (Alt+R to toggle). (3) Type in "\n\n+" (matches two or more consecutive newlines). (4) Hit Alt+Enter to multi-select all matches. (5) Hit Enter to replace all matches with a single newline. Commented Sep 27, 2016 at 18:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .